@reformer/builder 3.0.0-beta.5 → 3.0.0-beta.7

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 (167) hide show
  1. package/README.md +32 -198
  2. package/bin/reformer-builder.d.mts +7 -9
  3. package/bin/reformer-builder.mjs +43 -54
  4. package/dist/assets/css/index-DgRudQqc.css +1 -0
  5. package/dist/assets/css/monaco-runtime-Ch4loDnq.css +1 -0
  6. package/dist/assets/i18n/en-DHElWsPO.js +1 -0
  7. package/dist/assets/i18n/ru-DXsuKRv9.js +1 -0
  8. package/dist/assets/js/index-BSeq6-8S.js +67 -0
  9. package/dist/assets/js/index-CQvmAVe0.js +115 -0
  10. package/dist/assets/js/naming-9aaM0Wbc.js +1 -0
  11. package/dist/assets/js/rules-CM1OzesO.js +1 -0
  12. package/dist/assets/js/selectors-BiPlGN2c.js +1 -0
  13. package/dist/assets/monaco/html-R9lQ-L9C.js +1 -0
  14. package/dist/assets/monaco/javascript-COUjr2au.js +1 -0
  15. package/dist/assets/monaco/jsonMode-C3DAkvde.js +12 -0
  16. package/dist/assets/monaco/monaco-runtime-DNdOZY7f.js +924 -0
  17. package/dist/assets/monaco/typescript-CVSiBX9O.js +1 -0
  18. package/dist/assets/monaco/xml-ee1lph4p.js +1 -0
  19. package/dist/assets/monaco/yaml-DXPc9WLc.js +1 -0
  20. package/dist/assets/{byok-B9mwOrn0.js → plugins/ai-byok-DgeZQTZb.js} +55 -55
  21. package/dist/assets/plugins/ai-jKAVkXuU.js +178 -0
  22. package/dist/assets/plugins/ai-knowledge-docs-DCjqodcj.js +1 -0
  23. package/dist/assets/plugins/ai-knowledge-index-bUfNPqlZ.js +1 -0
  24. package/dist/assets/plugins/codegen-B0riFOHC.js +416 -0
  25. package/dist/assets/{MarkdownPreview-CmqjlfzE.js → plugins/editor-markdown-MarkdownPreview-DyHZvj8H.js} +20 -20
  26. package/dist/assets/plugins/editor-markdown-oiBrRpM4.js +2 -0
  27. package/dist/assets/plugins/editor-schema-CVPAk-MV.js +4 -0
  28. package/dist/assets/plugins/plugin-manager-BmjjSqYy.js +1 -0
  29. package/dist/assets/plugins/templates-DNeIl0cD.js +2 -0
  30. package/dist/assets/vendor/ajv-CCplthOF.js +8 -0
  31. package/dist/assets/vendor/collapsible-base-DZxAKbAF-h07cIL_F.js +1 -0
  32. package/dist/assets/vendor/highlight.js/common-g0-hl6Ud.js +5 -0
  33. package/dist/assets/vendor/index-jGqhTST4.js +6 -0
  34. package/dist/assets/vendor/lucide-react/eye-COs0olKf.js +1 -0
  35. package/dist/assets/vendor/lucide-react/file-code-corner-BMVX-Qf1.js +1 -0
  36. package/dist/assets/vendor/lucide-react/rotate-ccw-D0mVnqJN.js +1 -0
  37. package/dist/assets/vendor/lucide-react/wrench-BX6KiYsu.js +1 -0
  38. package/dist/assets/vendor/message-base-B5jT1FuY-GU8TkaN4.js +1 -0
  39. package/dist/assets/vendor/reformer-cdk/async-boundary-DPu-1Ifi.js +1 -0
  40. package/dist/assets/vendor/reformer-cdk/define-steps-CyGUrx9p-B_03D9I7.js +1 -0
  41. package/dist/assets/vendor/reformer-cdk/file-upload-C_DEa-OT.js +1 -0
  42. package/dist/assets/vendor/reformer-cdk/form-array-DRkRfAUh.js +1 -0
  43. package/dist/assets/vendor/reformer-cdk/form-wizard-DFqFjH7E.js +1 -0
  44. package/dist/assets/vendor/reformer-cdk/index-BXFomK5m.js +1 -0
  45. package/dist/assets/vendor/reformer-cdk/list-BrqYwhrQ.js +1 -0
  46. package/dist/assets/vendor/reformer-form-registry/index-s1IAa6Lm.js +1 -0
  47. package/dist/assets/vendor/reformer-form-registry/loader-BK2c_fCA-D59m3JOQ.js +2 -0
  48. package/dist/assets/vendor/reformer-form-registry/react-B8lbN6s4.js +1 -0
  49. package/dist/assets/vendor/reformer-form-registry/storage-BbhnRE7V.js +1 -0
  50. package/dist/assets/vendor/reformer-form-registry/types-DoMH_n1U-BSN9tyeo.js +1 -0
  51. package/dist/assets/vendor/reformer-renderer-json/validate-C5Gll2Yt.js +8 -0
  52. package/dist/assets/vendor/reformer-ui-kit/alert-base-WOl_V-qI-CYoSap05.js +1 -0
  53. package/dist/assets/vendor/reformer-ui-kit/component-catalog-BKjWf5Yx.js +1 -0
  54. package/dist/assets/{typescript-DL3gRsAd.js → vendor/typescript/typescript-Dp5hP5cS.js} +1 -1
  55. package/dist/index.html +4 -4
  56. package/package.json +15 -18
  57. package/runtime-config.schema.json +17 -60
  58. package/dist/assets/App-BupMDG_t.js +0 -1137
  59. package/dist/assets/BootError-CWnToysV.js +0 -1
  60. package/dist/assets/ChatPanel-B4wt7hBH.js +0 -82
  61. package/dist/assets/CodeEditor-Cca8j3Z3.js +0 -1
  62. package/dist/assets/RawJsonEditor-D5mwkIJa.js +0 -1
  63. package/dist/assets/abap-DLDM7-KI.js +0 -1
  64. package/dist/assets/apex-DNDY2TF8.js +0 -1
  65. package/dist/assets/azcli-Y6nb8tq_.js +0 -1
  66. package/dist/assets/bat-BwHxbl9M.js +0 -1
  67. package/dist/assets/bicep-CFznDFnq.js +0 -2
  68. package/dist/assets/boot-BCJd6Ujw.js +0 -2
  69. package/dist/assets/cameligo-Bf6VGUru.js +0 -1
  70. package/dist/assets/clojure-Dnu-v4kV.js +0 -1
  71. package/dist/assets/coffee-Bd8akH9Z.js +0 -1
  72. package/dist/assets/cpp-BbWJElDN.js +0 -1
  73. package/dist/assets/csharp-Co3qMtFm.js +0 -1
  74. package/dist/assets/csp-D-4FJmMZ.js +0 -1
  75. package/dist/assets/cypher-cTPe9QuQ.js +0 -1
  76. package/dist/assets/dart-BOtBlQCF.js +0 -1
  77. package/dist/assets/dockerfile-BG73LgW2.js +0 -1
  78. package/dist/assets/ecl-BEgZUVRK.js +0 -1
  79. package/dist/assets/editor-BzOv8av-.css +0 -1
  80. package/dist/assets/editor.api-BWDeQ8t4.js +0 -865
  81. package/dist/assets/elixir-BkW5O-1t.js +0 -1
  82. package/dist/assets/flow9-BeJ5waoc.js +0 -1
  83. package/dist/assets/freemarker2-DQaxDgne.js +0 -3
  84. package/dist/assets/fsharp-PahG7c26.js +0 -1
  85. package/dist/assets/go-acbASCJo.js +0 -1
  86. package/dist/assets/graphql-BxJiqAUM.js +0 -1
  87. package/dist/assets/handlebars-e1hbsCFi.js +0 -1
  88. package/dist/assets/hcl-DtV1sZF8.js +0 -1
  89. package/dist/assets/html-QXilGQ4Y.js +0 -1
  90. package/dist/assets/index-BLGbxQaR.js +0 -104
  91. package/dist/assets/index-BwhW-Atz.js +0 -3
  92. package/dist/assets/index-BxUg93Np.css +0 -1
  93. package/dist/assets/index-CF7RI8Bt.js +0 -68
  94. package/dist/assets/index-CLTXPf4k.js +0 -11
  95. package/dist/assets/index-Crsub4wy.js +0 -5028
  96. package/dist/assets/index-DhcNqNgT.js +0 -10
  97. package/dist/assets/index-DzAasWzr.css +0 -1
  98. package/dist/assets/index-U9gpmElw.js +0 -4709
  99. package/dist/assets/index-eRs9yupj.js +0 -1
  100. package/dist/assets/ini-Kd9XrMLS.js +0 -1
  101. package/dist/assets/java-CXBNlu9o.js +0 -1
  102. package/dist/assets/javascript-C7cOj8ds.js +0 -1
  103. package/dist/assets/jsonMode-BgHFRVOe.css +0 -1
  104. package/dist/assets/jsonMode-DEqS3I0B.js +0 -70
  105. package/dist/assets/julia-cl7-CwDS.js +0 -1
  106. package/dist/assets/kotlin-s7OhZKlX.js +0 -1
  107. package/dist/assets/less-9HpZscsL.js +0 -2
  108. package/dist/assets/lexon-OrD6JF1K.js +0 -1
  109. package/dist/assets/liquid-grdNDW6i.js +0 -1
  110. package/dist/assets/load-QsSQTL2T.js +0 -11
  111. package/dist/assets/lua-Cyyb5UIc.js +0 -1
  112. package/dist/assets/m3-B8OfTtLu.js +0 -1
  113. package/dist/assets/mdx-BGpbXlZS.js +0 -1
  114. package/dist/assets/mips-CiqrrVzr.js +0 -1
  115. package/dist/assets/monaco-languages-BZWxuU3F.js +0 -2
  116. package/dist/assets/monaco-setup-1PbjxubL.js +0 -12
  117. package/dist/assets/msdax-DmeGPVcC.js +0 -1
  118. package/dist/assets/mysql-C_tMU-Nz.js +0 -1
  119. package/dist/assets/objective-c-BDtDVThU.js +0 -1
  120. package/dist/assets/pascal-vHIfCaH5.js +0 -1
  121. package/dist/assets/pascaligo-DtZ0uQbO.js +0 -1
  122. package/dist/assets/perl-Ub6l9XKa.js +0 -1
  123. package/dist/assets/pgsql-BlNEE0v7.js +0 -1
  124. package/dist/assets/php-BBUBE1dy.js +0 -1
  125. package/dist/assets/pla-DSh2-awV.js +0 -1
  126. package/dist/assets/postiats-CocnycG-.js +0 -1
  127. package/dist/assets/powerquery-tScXyioY.js +0 -1
  128. package/dist/assets/powershell-COWaemsV.js +0 -1
  129. package/dist/assets/protobuf-Brw8urJB.js +0 -2
  130. package/dist/assets/pug-8SOpv6rk.js +0 -1
  131. package/dist/assets/python-D5X7CY5Y.js +0 -1
  132. package/dist/assets/qsharp-Bw9ernYp.js +0 -1
  133. package/dist/assets/r-j7ic8hl3.js +0 -1
  134. package/dist/assets/razor-B2pbhZKy.js +0 -1
  135. package/dist/assets/redis-Bu5POkcn.js +0 -1
  136. package/dist/assets/redshift-Bs9aos_-.js +0 -1
  137. package/dist/assets/reformer-ui-kit-11-bLtlFFvp.js +0 -1
  138. package/dist/assets/reformer-ui-kit-tUqYBSLv.js +0 -1
  139. package/dist/assets/restructuredtext-CqXO7rUv.js +0 -1
  140. package/dist/assets/ruby-zBfavPgS.js +0 -1
  141. package/dist/assets/rust-BzKRNQWT.js +0 -1
  142. package/dist/assets/sb-BBc9UKZt.js +0 -1
  143. package/dist/assets/scala-D9hQfWCl.js +0 -1
  144. package/dist/assets/scheme-BPhDTwHR.js +0 -1
  145. package/dist/assets/scss-CBJaRo0y.js +0 -3
  146. package/dist/assets/shell-DiJ1NA_G.js +0 -1
  147. package/dist/assets/solidity-Db0IVjzk.js +0 -1
  148. package/dist/assets/sophia-CnS9iZB_.js +0 -1
  149. package/dist/assets/sparql-CJmd_6j2.js +0 -1
  150. package/dist/assets/sql-ClhHkBeG.js +0 -1
  151. package/dist/assets/st-CHwy0fLd.js +0 -1
  152. package/dist/assets/swift-CnmFD0ga.js +0 -1
  153. package/dist/assets/systemverilog-Bs9z6M-B.js +0 -1
  154. package/dist/assets/tcl-Dm6ycUr_.js +0 -1
  155. package/dist/assets/twig-Csy3S7wG.js +0 -1
  156. package/dist/assets/typescript-Ccn-IGn9.js +0 -1
  157. package/dist/assets/typespec-Btyra-wh.js +0 -1
  158. package/dist/assets/useFormField-BLbvmpme-Dwz_jyMW.js +0 -1
  159. package/dist/assets/vb-Db0cS2oM.js +0 -1
  160. package/dist/assets/wgsl-BTesnYfV.js +0 -298
  161. package/dist/assets/xml-NgTjWpvZ.js +0 -1
  162. package/dist/assets/yaml-CboCRslW.js +0 -1
  163. /package/dist/assets/{codicon-Brq4_Ui5.ttf → fonts/codicon-Brq4_Ui5.ttf} +0 -0
  164. /package/dist/assets/{css-DdJfP1eB.js → monaco/css-DdJfP1eB.js} +0 -0
  165. /package/dist/assets/{editor.worker-CRaYpIdo.js → monaco/editor.worker-CRaYpIdo.js} +0 -0
  166. /package/dist/assets/{json.worker-C5PEkLU0.js → monaco/json.worker-C5PEkLU0.js} +0 -0
  167. /package/dist/assets/{markdown-BFxVWTOG.js → monaco/markdown-BFxVWTOG.js} +0 -0
@@ -0,0 +1 @@
1
+ const r=1,e="2026-09-09T19:56:12.368Z",n=JSON.parse('{"@reformer/core":{"schemaVersion":1,"package":"@reformer/core","version":"6.0.0","topics":[{"id":"api-reference","file":"01-api-reference.md","title":"api-reference","purpose":"Архитектура M1: значения живут в **модели** (`createModel`), а форма (`createForm`) строит ноды поверх сигналов модели. Behaviors работают на сигналах (`model.$.field`), а не на строковых путях.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"1. API Reference","slug":"api-reference"}],"terms":[["reformer",18],["core",18],["behaviors",6],["value",6],["model",5],["useformcontrolvalue",5],["loantype",5],["createform",4],["validate",4],["useformcontrol",4],["type",4],["field",3],["validation",3],["computefrom",3],["copyfrom",3],["enablewhen",3],["примитивы",3],["required",3],["min",3],["validators",3],["null",3],["только",3],["form",3],["const",3],["control",3],["critically",2],["important",2],["живут",2],["модели",2],["createmodel",2],["ноды",2],["validatemodel",2],["definevalidationschema",2],["apply",2],["rule",2],["usearraylength",2],["validationerror",2],["watchfield",2],["disablewhen",2],["transformvalue",2],["resetwhen",2],["syncfields",2],["revalidatewhen",2],["email",2],["defineformbehavior",2],["compute",2],["сигналы",2],["возвращают",2],["cleanup",2],["сам",2],["schema",2],["опциональные",2],["number",2],["string",2],["errors",2],["disabled",2],["поля",2],["напрямую",2],["длина",2],["массива",2],["correct",2]]},{"id":"quick-start","file":"02-quick-start.md","title":"quick-start","purpose":"Архитектура M1: **модель данных** — источник истины, схема привязывает поля к её сигналам (`model.$.field`), а сборка идёт ОДНИМ вызовом `createCoreForm` (для рендера ui-kit; в рендерерах — `createReactForm` / `createJsonForm`), который создаёт модель, строит форму, запускает поведение и собирает валидацию. Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной схеме `defineValidationSchema` из `@reformer/core/validation` и запускается внешним раннером `validateModel(model, schema)`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"1.5 QUICK START - Minimal Working Form","slug":"quick-start-minimal-working-form"}],"terms":[["model",23],["form",19],["type",15],["schema",13],["email",13],["name",12],["const",11],["componentprops",10],["item",10],["component",9],["reformer",9],["label",8],["formfield",7],["properties",7],["kit",5],["field",5],["core",5],["validation",5],["required",5],["contactform",5],["value",5],["array",5],["propertyitem",5],["схеме",4],["control",4],["createcoreform",4],["validatemodel",4],["import",4],["from",4],["validate",4],["inputfield",4],["react",4],["модели",4],["под",4],["description",4],["estimatedvalue",4],["options",3],["поля",3],["jsx",3],["один",3],["props",3],["модель",3],["схема",3],["валидация",3],["definevalidationschema",3],["createmodel",3],["button",3],["string",3],["contactvalidation",3],["message",3],["submit",3],["testid",3],["элемента",3],["myform",3],["driven",2],["его",2],["placeholder",2],["объявляются",2],["без",2],["свои",2],["input",2],["find_recipe",2],["topic",2],["источник",2],["истины",2],["сборка",2],["одним",2],["вызовом",2],["для",2],["который",2],["строит",2],["валидацию",2],["layout",2],["отдельной",2],["typescript",2],["useformbundle",2],["formproxy",2],["validators",2],["not",2],["your",2],["ноды",2],["раз",2],["contact",2],["function",2],["handlesubmit",2],["async",2],["только",2],["return",2],["components",2],["formstepprops",2],["через",2],["arrays",2],["formmodel",2],["apartment",2],["number",2]]},{"id":"api-signatures","file":"03-api-signatures.md","title":"api-signatures","purpose":"// Форма (ноды поверх сигналов модели) createForm<T>({ model, schema, behavior? }): FormProxy<T> // form.<field> → FieldNode / GroupNode / FormArrayProxy // form.<field>.setValue(v) / .value.value / .errors.value / .disabled.value // form.<field>.enable() / .disable() / .reset() / .markAsTouched() / .setErrors([...]) // form.<field>.updateComponentProps({ ... })","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"2. API SIGNATURES","slug":"api-signatures"}],"terms":[["model",64],["value",29],["options",29],["string",29],["message",25],["validate",20],["const",19],["reformer",17],["core",17],["boolean",15],["email",15],["void",15],["required",14],["form",13],["cross",13],["field",12],["validatemodel",12],["null",12],["typescript",11],["number",11],["signal",11],["definevalidationschema",10],["import",10],["from",10],["createform",9],["schema",9],["apply",9],["item",8],["validation",8],["validators",8],["над",8],["rule",8],["min",8],["правила",8],["type",8],["each",7],["validationschema",6],["sig",6],["внутри",6],["age",6],["validatewhen",6],["confirm",6],["readonlysignal",6],["target",6],["enablewhen",6],["formmodel",5],["get",5],["только",5],["layout",5],["схема",5],["моделью",5],["validationerror",5],["date",5],["поля",5],["amount",5],["под",5],["операторы",5],["never",5],["asyncrule",5],["per",5],["country",5],["length",4],["модели",4],["behavior",4],["seterrors",4],["валидация",4],["раннер",4],["ошибки",4],["promise",4],["валидации",4],["await",4],["scope",4],["root",4],["validateasync",4],["async",4],["password",4],["code",4],["return",4],["при",4],["для",4],["loanform",4],["computefrom",4],["copyfrom",4],["resetondisable",4],["revalidatewhen",4],["compute",4],["api",3],["модель",3],["createmodel",3],["enable",3],["дерево",3],["несёт",3],["функция",3],["внешний",3],["submit",3],["схемы",3],["max",3],["loan",3],["component",3],["inputfield",3],["abortsignal",3],["cond",3],["условная",3],["ветка",3],["это",3],["поведение",3],["снапшот",3],["массива",3],["композиция",3],["той",3],["signup",3],["loantype",3],["step1",3],["step5",3],["income",3],["formvalidation",3],["step_schemas",3],["behaviors",3],["when",3],["condition",3],["city",3],["true",3],["onchange",3],["данных",2],["reset",2],["сигналу",2],["modelarray",2],["ноды",2],["поверх",2],["errors",2],["updatecomponentprops",2],["отдельный",2],["контракт",2],["без",2],["формы",2],["warning",2],["блокирует",2],["устаревший",2],["прогон",2],["отменяется",2],["валидацию",2],["фабрики",2],["возвращают",2],["правило",2],["принимают",2],["validator",2],["factories",2],["years",2],["отдельной",2],["схеме",2],["loanvalidation",2],["сами",2],["обычная",2],["текущего",2],["прогона",2],["ниже",2],["ctx",2],["rules",2],["активны",2],["гасятся",2],["err",2],["получает",2],["arr",2],["schemas",2],["only",2],["strongpassword",2],["вешается",2],["через",2],["passwordsmatch",2],["emailunique",2],["res",2],["ветки",2],["элемента",2],["step",2],["mortgage",2],["полная",2],["cleanup",2],["vals",2],["source",2],["transform",2],["immediate",2],["disablewhen",2],["transformvalue",2],["resetwhen",2],["syncfields",2],["cleanups",2],["price",2],["quantity",2],["total",2],["dsl",2],["defineformbehavior",2]]},{"id":"common-patterns","file":"04-common-patterns.md","title":"common-patterns","purpose":"Все паттерны — на архитектуре M1: значения в модели (`model.$.field`), поведение (`defineFormBehavior`) на живых сигналах, валидация — отдельной ambient-схемой (`defineValidationSchema`, прогон по требованию через `validateModel`). Слои раздельны: layout НЕ несёт validators.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"3. COMMON PATTERNS","slug":"common-patterns"}],"terms":[["model",42],["reformer",15],["core",15],["import",14],["from",14],["const",14],["cross",12],["defineformbehavior",10],["typescript",10],["field",9],["value",9],["validation",9],["validatemodel",7],["myform",7],["initialpayment",7],["модели",6],["definevalidationschema",6],["propertyvalue",6],["compute",6],["validate",6],["null",6],["валидация",5],["loantype",5],["async",5],["onchange",5],["для",5],["form",5],["region",5],["schema",5],["правило",5],["required",5],["поведение",4],["enablewhen",4],["при",4],["внутри",4],["behaviors",4],["behavior",4],["computefrom",4],["price",4],["options",4],["поля",4],["return",4],["email",4],["get",4],["validationerror",4],["rule",4],["validatewhen",4],["revalidatewhen",4],["через",3],["validators",3],["reset",3],["mortgage",3],["signal",3],["await",3],["react",3],["submit",3],["ошибки",3],["формы",3],["false",3],["ошибка",3],["под",3],["min",3],["initialpaymentvsproperty",3],["validateadultage",3],["требованию",2],["layout",2],["conditional",2],["auto",2],["поле",2],["initial",2],["resetondisable",2],["true",2],["computed",2],["сигнал",2],["изменении",2],["источников",2],["источники",2],["кросс",2],["total",2],["quantity",2],["qty",2],["fullname",2],["personaldata",2],["boolean",2],["вне",2],["effect",2],["ноды",2],["abortsignal",2],["city",2],["updatecomponentprops",2],["cities",2],["debounce",2],["без",2],["напрямую",2],["снимок",2],["есть",2],["блокирующая",2],["multi",2],["step",2],["схемы",2],["шаг",2],["validateall",2],["получает",2],["type",2],["снапшот",2],["читается",2],["как",2],["code",2],["message",2],["item",2],["модель",2],["правила",2],["мост",2],["схема",2],["age",2],["new",2],["date",2],["getfullyear",2]]},{"id":"common-mistakes","file":"05-common-mistakes.md","title":"common-mistakes","purpose":"- Модель/форма/хуки/типы (`FormModel`, `ValidationError`)/**примитивы behaviors** — из `@reformer/core`. - Схема валидации (`defineValidationSchema` + операторы `validate`/`validateAsync`/`validateWhen`/`cross`/`each`/`apply`) и раннер `validateModel` — из `@reformer/core/validation`. - Чистые фабрики валидаторов (`required`/`min`/`email`/…) — из `@reformer/core/validators`. - Декларативный DSL поведения (`defineFormBehavior` + операторы) — из `@reformer/core/behaviors`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"4. COMMON MISTAKES","slug":"common-mistakes"}],"terms":[["model",23],["email",17],["value",14],["reformer",13],["core",13],["type",13],["const",11],["cross",9],["form",9],["validate",8],["typescript",8],["amount",8],["required",7],["behaviors",6],["correct",6],["import",6],["useformcontrolvalue",6],["from",6],["loantype",6],["null",6],["ctx",6],["definevalidationschema",5],["validatemodel",5],["validators",5],["price",5],["validateasync",4],["dsl",4],["через",4],["wrong",4],["total",4],["rate",4],["validationerror",3],["схема",3],["операторы",3],["раннер",3],["validation",3],["min",3],["useformcontrol",3],["computefrom",3],["enablewhen",3],["compute",3],["для",3],["get",3],["submit",3],["control",3],["api",3],["path",3],["quantity",3],["values",3],["оператор",3],["layout",3],["schema",3],["myform",3],["message",3],["await",3],["field",3],["interface",3],["string",3],["instanceof",3],["rule",2],["errors",2],["модель",2],["форма",2],["хуки",2],["formmodel",2],["примитивы",2],["валидации",2],["validatewhen",2],["each",2],["apply",2],["фабрики",2],["декларативный",2],["поведения",2],["defineformbehavior",2],["createform",2],["отдельный",2],["слой",2],["validationschema",2],["max",2],["либо",2],["onchange",2],["watchfield",2],["значения",2],["модели",2],["ноды",2],["returns",2],["сигналы",2],["пути",2],["старый",2],["удалён",2],["city",2],["boolean",2],["country",2],["qty",2],["валидаторы",2],["валидация",2],["json",2],["прогон",2],["внутри",2],["emailschema",2],["signal",2],["res",2],["free",2],["code",2],["setfieldvalue",2],["root",2],["amountvsmax",2],["maxamount",2],["export",2],["propertyitem",2],["propertytype",2],["description",2],["proxy",2],["node",2],["isfieldnode",2]]},{"id":"troubleshooting","file":"06-troubleshooting.md","title":"troubleshooting","purpose":"","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"5. TROUBLESHOOTING","slug":"troubleshooting"}],"terms":[["reformer",4],["core",4],["model",3],["string",2],["message",2],["вместо",2],["useformcontrolvalue",2],["без",2],["поле",2],["cycle",2],["модели",2],["field",2],["ошибки",2],["submit",2],["validatemodel",2],["schema",2]]},{"id":"complete-import","file":"07-complete-import.md","title":"complete-import","purpose":"// Типы import type { FormModel, // реактивная модель данных FormProxy, // тип формы для props компонентов FieldNode, // узел одного поля GroupNode, // узел группы ArrayNode, // узел массива ModelArray, // реактивный массив модели (push/removeAt/at/map/length) ModelSignals, // дерево сигналов ($) PathAwareSignal, // сигнал, знающий свой путь ValidationError, FieldConfig, // { value, component, componentProps?, ... } — layout, БЕЗ валидаторов FormSchema, FieldControlState, } from \'@reformer/core\';","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Import Patterns","slug":"import-patterns"}],"terms":[["import",7],["reformer",7],["core",7],["type",7],["from",6],["behaviors",5],["string",5],["типы",4],["узел",3],["validationerror",3],["value",3],["validation",3],["form",3],["shape",3],["typescript",2],["модель",2],["хуки",2],["примитивы",2],["фабрики",2],["createform",2],["computefrom",2],["copyfrom",2],["enablewhen",2],["disablewhen",2],["transformvalue",2],["resetwhen",2],["syncfields",2],["revalidatewhen",2],["тип",2],["groupnode",2],["группы",2],["arraynode",2],["массива",2],["раннер",2],["validate",2],["apply",2],["validatemodel",2],["promise",2],["null",2],["validators",2],["interface",2],["export",2]]},{"id":"form-types","file":"08-form-types.md","title":"form-types","purpose":"Form-shape объявляй через `type`-alias (не `interface` — см. `30-type-safety-recipes.md`). Тип описывает форму ДАННЫХ (то, что кладётся в `createModel`), без узлов/сигналов.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"7. FORM TYPE DEFINITION","slug":"form-type-definition"}],"terms":[["string",8],["null",8],["type",5],["form",3],["name",3],["definition",2],["createmodel",2],["myform",2],["fields",2],["email",2],["phone",2],["age",2],["number",2],["status",2],["active",2],["objects",2],["address",2],["street",2],["city",2],["arrays",2],["model",2],["items",2]]},{"id":"formschema","file":"09-formschema.md","title":"formschema","purpose":"Под M1 схема **привязывает поле к сигналу модели** (`value: model.$.field`) и держит UI-конфиг (`component`/`componentProps`). Значения принадлежат модели. Валидаторов в layout-схеме НЕТ — правила живут в отдельной схеме `defineValidationSchema` из `@reformer/core/validation` и запускаются раннером `validateModel(model, schema)`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"8. SCHEMA FORMAT (CRITICALLY IMPORTANT)","slug":"schema-format-critically-important"}],"terms":[["model",21],["value",16],["component",12],["componentprops",12],["label",12],["name",11],["schema",10],["const",10],["item",10],["модели",9],["reformer",9],["inputfield",9],["form",9],["core",8],["formmodel",8],["typescript",7],["import",7],["createform",7],["from",7],["address",7],["city",7],["myform",6],["под",5],["type",5],["age",4],["agree",4],["status",4],["items",4],["поле",3],["field",3],["definevalidationschema",3],["node",3],["disabled",3],["это",3],["active",3],["street",3],["zip",3],["array",3],["proxy",3],["important",2],["схема",2],["схеме",2],["validation",2],["validatemodel",2],["сигнал",2],["обязателен",2],["placeholder",2],["options",2],["number",2],["узла",2],["состояние",2],["createmodel",2],["validate",2],["required",2],["selectfield",2],["checkboxfield",2],["myvalidation",2],["inactive",2],["sub",2],["api",2],["builder",2],["элемента",2],["массива",2],["addressnodes",2],["itemschema",2],["behavior",2],["доступ",2],["через",2],["тип",2],["formschema",2],["fieldnode",2],["string",2],["isfieldnode",2]]},{"id":"arrays","file":"10-arrays.md","title":"arrays","purpose":"Массивы объектов — **model-owned**: данные принадлежат модели (`model.arrayField` — это `ModelArray<Item>` с реактивными `push`/`removeAt`/`length`). В схеме массив объявляется узлом `{ array: model.<path>, item: (itemModel) => subSchema }`, где `item` строит под-схему одного элемента из его под-модели (`FormModel<Item>`).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[03-api-signatures.md](./03-api-signatures.md) — сигнатуры нод `form.<array>` / `ModelArray`, per-item валидация `each`","CDK / ui-kit form-array (`FormArray.Root`, `FormArraySection`) — `find_recipe(topic=\\"form-array\\")`"],"sections":[{"heading":"9. ARRAY SCHEMA FORMAT","slug":"array-schema-format"},{"heading":"See also","slug":"see-also"}],"terms":[["item",36],["model",34],["items",23],["array",17],["form",15],["name",10],["type",8],["reformer",8],["price",8],["myform",8],["properties",8],["под",7],["createform",7],["validation",7],["typescript",6],["const",6],["через",6],["each",6],["control",6],["schema",5],["push",5],["length",5],["элемента",5],["formmodel",5],["from",5],["core",5],["value",5],["component",5],["модели",4],["схеме",4],["массив",4],["import",4],["inputfield",4],["kit",4],["per",4],["formarraysection",4],["index",4],["map",4],["div",4],["button",4],["cross",4],["names",4],["modelarray",3],["removeat",3],["path",3],["его",3],["string",3],["схема",3],["field",3],["внутри",3],["definevalidationschema",3],["модель",3],["cdk",3],["formarray",3],["root",3],["массива",3],["формы",3],["плоские",3],["значения",3],["clear",3],["hasitems",3],["это",2],["itemmodel",2],["subschema",2],["одного",2],["createmodel",2],["number",2],["сигнал",2],["itemschema",2],["componentprops",2],["три",2],["только",2],["layout",2],["форма",2],["схемы",2],["для",2],["правила",2],["оператором",2],["validate",2],["required",2],["или",2],["itemcomponent",2],["валидация",2],["insertat",2],["при",2],["behavior",2],["выше",2],["formproxy",2],["usearraylength",2],["return",2],["formfield",2],["onclick",2],["remove",2],["add",2],["find_recipe",2],["topic",2],["sig",2],["поле",2],["носитель",2],["api",2],["signatures",2]]},{"id":"async-watchfield","file":"11-async-watchfield.md","title":"async-watchfield","purpose":"Для async-реакции на изменение поля (загрузка зависимых опций, справочников) используй `onChange` из `@reformer/core/behaviors`. Колбэк выполняется ВНЕ effect-контекста (можно безопасно писать сигналы/ноды), а 2-й аргумент — `{ signal }` (AbortSignal): при следующей смене значения предыдущий вызов аннулируется — передавай `signal` в `fetch`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"10. ASYNC REACTION — onChange (CRITICALLY IMPORTANT)","slug":"async-reaction-onchange-critically-important"}],"terms":[["onchange",7],["async",4],["reformer",4],["core",4],["signal",4],["model",4],["form",4],["watchfield",4],["при",3],["const",3],["value",3],["dependentfield",3],["updatecomponentprops",3],["options",3],["error",3],["debounce",3],["для",2],["изменение",2],["поля",2],["behaviors",2],["колбэк",2],["abortsignal",2],["fetch",2],["typescript",2],["import",2],["defineformbehavior",2],["from",2],["return",2],["try",2],["data",2],["catch",2],["aborterror",2],["умолчанию",2],["stop",2],["country",2]]},{"id":"array-cleanup","file":"12-array-cleanup.md","title":"array-cleanup","purpose":"Очистка массива при выключении флага — через `onChange` на сигнале флага + `clear()` на модели-массиве. Колбит выполняется вне effect-контекста, поэтому мутировать массив безопасно.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"11. ARRAY CLEANUP PATTERN","slug":"array-cleanup-pattern"}],"terms":[["onchange",5],["model",5],["clear",4],["array",3],["флага",3],["import",3],["from",3],["reformer",3],["core",3],["behaviors",3],["hasitems",3],["при",2],["массив",2],["typescript",2],["defineformbehavior",2],["readonlysignal",2],["clearwhenoff",2],["flag",2],["void",2]]},{"id":"multi-step","file":"13-multi-step.md","title":"multi-step","purpose":"Каждый шаг — своя `ValidationSchema<Form>` (обычная функция `({ model }) => void`, обёрнутая `defineValidationSchema`). Переход к следующему шагу проверяется `validateModel(model, stepSchema)`; полный submit — по общей схеме (композиция шагов через `apply(...)`). `validateModel` сам разносит ошибки по нодам формы (`getNodeForSignal(sig).setErrors(...)`), поэтому UI подсветит проблемные поля текущего шага автоматически. Валидация живёт ОТДЕЛЬНО от layout: сам `RenderNode`/JSON-узел валидаторов не несёт — схема инъектируется в рантайме и роутит ошибки по тем же нодам.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"12. MULTI-STEP FORM VALIDATION","slug":"multi-step-form-validation"}],"terms":[["model",17],["step",12],["form",11],["const",11],["validatemodel",9],["validate",6],["definevalidationschema",5],["required",5],["step_schemas",5],["apply",4],["await",4],["button",4],["validationschema",3],["submit",3],["ошибки",3],["шага",3],["схема",3],["typescript",3],["import",3],["from",3],["reformer",3],["core",3],["fullschema",3],["promise",3],["boolean",3],["async",3],["return",3],["setstep",3],["multi",2],["validation",2],["обычная",2],["функция",2],["void",2],["переход",2],["следующему",2],["шагу",2],["полный",2],["общей",2],["схеме",2],["композиция",2],["шагов",2],["через",2],["сам",2],["нодам",2],["sig",2],["текущего",2],["автоматически",2],["type",2],["formmodel",2],["min",2],["под",2],["step1schema",2],["step2schema",2],["personaldata",2],["currentstep",2],["handlesubmit",2],["function",2],["nextstep",2],["div",2],["onclick",2]]},{"id":"extended-mistakes","file":"14-extended-mistakes.md","title":"extended-mistakes","purpose":"// ✅ apply — одна под-схема на несколько групп const addressBehavior = defineFormBehavior<Address>(({ model }) => { compute(model.$.full, () => `${model.city}, ${model.street}`); });","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"13. EXTENDED COMMON MISTAKES","slug":"extended-common-mistakes"}],"terms":[["model",35],["compute",11],["cross",8],["reformer",6],["core",6],["const",6],["form",6],["field1",6],["apply",5],["typescript",5],["root",5],["applyeach",4],["import",4],["defineformbehavior",4],["from",4],["row",4],["field",4],["scope",4],["validate",4],["validatemodel",4],["value",4],["transformvalue",3],["цикл",3],["prefix",3],["firstname",3],["cycle",3],["detected",3],["валидации",3],["validation",3],["правило",3],["ошибки",3],["validators",3],["validateformmodel",3],["field2",3],["null",3],["schema",3],["под",2],["схема",2],["addressbehavior",2],["qty",2],["price",2],["setvalue",2],["guard",2],["ручной",2],["onchange",2],["запись",2],["fullname",2],["lastname",2],["peek",2],["без",2],["стабилизации",2],["поля",2],["или",2],["через",2],["валидация",2],["sig",2],["поле",2],["читает",2],["get",2],["definevalidationschema",2],["required",2],["revalidatewhen",2],["validationerror",2],["modelvalidator",2],["legacyrule",2],["code",2],["error",2],["message",2],["invalid",2],["legacyschema",2],["field1lessthanfield2",2],["только",2],["api",2],["ctx",2]]},{"id":"project-structure","file":"15-project-structure.md","title":"project-structure","purpose":"One form is one module folder. **Default layout — flat minimalist:** every concern is a single file at the module root, and the whole form (entry + all wizard steps inline) lives in one `index.tsx`. Filenames are flat with no prefix — **the dot-prefix (`form.` / `renderer.`) is carried only by `schema` and `behavior`**, the two concerns that have both a model-layer and a render-layer version (`form.schema.ts` / `form.behavior.ts` here; renderer slices add `renderer.schema.*` / `renderer.behavior.ts`). No `lib/` / `schema/` / `components/steps/` nesting until the form grows (see \\"Scaling up\\" below). Arrays are declared in `form.schema.ts` and rendered with `FormArraySection` — no per-step component files.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"14. PROJECT STRUCTURE (COLOCATION)","slug":"project-structure-colocation"}],"terms":[["form",35],["the",28],["model",24],["schema",22],["behavior",14],["forms",14],["one",12],["steps",11],["renderer",11],["validation",11],["module",10],["index",10],["tsx",9],["component",9],["layout",7],["file",7],["and",7],["entry",7],["components",7],["step",7],["all",6],["with",6],["type",6],["folders",6],["flat",5],["root",5],["lib",5],["per",5],["value",5],["credit",5],["application",5],["export",5],["creditapplicationform",5],["loantype",5],["reformer",5],["folder",4],["default",4],["minimalist",4],["concern",4],["inline",4],["reusable",4],["createcoreform",4],["types",4],["createmodel",4],["defineformbehavior",4],["for",4],["import",4],["formmodel",4],["from",4],["core",4],["const",4],["structure",3],["single",3],["whole",3],["wizard",3],["only",3],["scaling",3],["formarraysection",3],["files",3],["formwizard",3],["option",3],["array",3],["factories",3],["compute",3],["enablewhen",3],["data",3],["sources",3],["api",3],["tree",3],["when",3],["personaldata",3],["large",3],["domain",3],["react",3],["every",2],["lives",2],["are",2],["prefix",2],["concerns",2],["that",2],["layer",2],["see",2],["below",2],["arrays",2],["name",2],["call",2],["enums",2],["label",2],["dictionaries",2],["initial",2],["values",2],["element",2],["componentprops",2],["validatestep",2],["validateall",2],["submit",2],["rule",2],["thumb",2],["this",2],["createcreditapplicationmodel",2],["creditapplicationschema",2],["properties",2],["creditapplicationbehavior",2],["monthlypayment",2],["renders",2],["createcreditapplicationform",2],["builder",2],["you",2],["sub",2],["calc",2],["validators",2],["raw",2],["material",2],["definition",2],["plus",2],["target",2],["nested",2],["cross",2],["guide",2],["mcp",2],["variants",2],["json",2],["directory",2]]},{"id":"ui-components","file":"16-ui-components.md","title":"ui-components","purpose":"type RegistrationForm = { email: string; country: string; agree: boolean; };","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"❌ **Свои field-компоненты с label-prop\'ами в JSX**:\\n\\n```tsx\\n// WRONG — дублирует логику FormField, ломает schema-driven архитектуру\\n<Input control={form.email} label=\\"Email\\" placeholder=\\"...\\" />\\n<Select control={form.country} options={[...]} />\\n```\\n\\n❌ **Передача компонент-пропсов через JSX вместо схемы**:\\n\\n```tsx\\n// WRONG — нарушает single source of truth (схема)\\n<FormField control={form.email} label=\\"Email\\" />\\n```\\n\\n✅ Всё это в схеме:\\n\\n```ts\\n{ email: { component: InputField, componentProps: { label: \'Email\' } } }\\n```\\n\\n```tsx\\n<FormField control={form.email} />\\n```"}],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"14.5 UI COMPONENT PATTERNS","slug":"ui-component-patterns"}],"terms":[["label",24],["control",22],["formfield",16],["componentprops",16],["email",16],["form",15],["value",15],["reformer",11],["input",11],["string",11],["type",10],["from",10],["kit",9],["import",9],["placeholder",8],["tsx",8],["country",8],["agree",7],["const",7],["component",6],["useformcontrol",6],["errors",6],["disabled",6],["для",5],["schema",5],["options",5],["jsx",5],["model",5],["testid",5],["через",5],["обёртки",4],["если",4],["inputfield",4],["без",4],["return",4],["span",4],["свои",3],["field",3],["driven",3],["компонент",3],["как",3],["select",3],["etc",3],["props",3],["react",3],["core",3],["button",3],["registrationform",3],["function",3],["компоненты",3],["prop",3],["onchange",3],["fieldnode",3],["один",3],["myformfield",3],["unknown",3],["patterns",2],["default",2],["используй",2],["пиши",2],["design",2],["system",2],["особый",2],["подход",2],["схеме",2],["integration",2],["usememo",2],["createmodel",2],["createform",2],["selectfield",2],["checkboxfield",2],["сам",2],["всё",2],["wrong",2],["вместо",2],["схемы",2],["advanced",2],["children",2],["inputmask",2],["mask",2],["phone",2],["onblur",2],["myformfieldprops",2],["shouldshowerror",2],["record",2],["text",2],["setvalue",2],["target",2],["message",2],["рендерер",2],["renderer",2],["components",2],["div",2],["classname",2]]},{"id":"nonexistent-api","file":"17-nonexistent-api.md","title":"nonexistent-api","purpose":"**Следующего API НЕТ в @reformer/core** (наследие старой path-based архитектуры, удалено при переходе на M1 и при разделении валидации/поведения):","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"15. NON-EXISTENT API (DO NOT USE)","slug":"non-existent-api-do-not-use"}],"terms":[["model",21],["reformer",13],["core",13],["value",12],["form",11],["нет",10],["import",10],["validators",9],["from",9],["validate",8],["validatemodel",8],["email",8],["definevalidationschema",6],["layout",6],["валидации",5],["cross",5],["validation",5],["correct",5],["schema",5],["field",5],["name",5],["type",5],["validatewhen",4],["each",4],["раннер",4],["wrong",4],["submit",4],["behaviors",4],["typescript",4],["поведение",4],["api",3],["path",3],["при",3],["ambient",3],["схема",3],["useform",3],["boolean",3],["схему",3],["существует",3],["component",3],["common",3],["required",3],["revalidatewhen",3],["const",3],["операторы",2],["validateasync",2],["apply",2],["живут",2],["createmodel",2],["createform",2],["хука",2],["validateform",2],["validateformmodel",2],["внешний",2],["await",2],["прогон",2],["applywhen",2],["валидация",2],["оператором",2],["validationschemafn",2],["validationschema",2],["defineformbehavior",2],["equalto",2],["rule",2],["sig",2],["запускают",2],["fieldpath",2],["пути",2],["ctx",2],["compute",2],["transformers",2],["useformcontrolvalue",2],["useformcontrol",2],["отдельный",2],["mistakes",2],["поле",2],["сигналу",2],["правила",2],["литерал",2],["модели",2],["inputfield",2],["componentprops",2],["label",2],["enablewhen",2],["city",2],["country",2]]},{"id":"conditional-fields","file":"18-conditional-fields.md","title":"Условные поля — видимость, доступность и валидация","purpose":"«Показать поле X только если Y» под M1 решается тремя независимыми механизмами — выбирай по тому, что именно должно быть условным:","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"Условную валидацию раньше собирали иначе; эти формы удалены при переходе на `@reformer/core/validation`.\\nНиже — **как НЕ надо** (чтобы не регрессировать); рабочий вариант — `validateWhen` из раздела выше.\\n\\n- **Нет branch-узла `{ when, children }` в дереве схемы.** Старая схема была деревом\\n `{ value, validators: [...] }` с ветками `{ when: (scope, root) => boolean, children: [...] }`,\\n которое обходил `validateFormModel`. Теперь схема — функция `({ model }) => void`, а условие —\\n оператор `validateWhen(() => cond, () => {…})`; отдельного объекта-узла нет.\\n\\n ```typescript\\n // УДАЛЕНО — так больше нельзя\\n const schema = {\\n children: [\\n { value: model.$.loanType, validators: [required()] },\\n { when: (_s, root) => root.loanType === \'mortgage\', children: [ /* … */ ] },\\n ],\\n };\\n await validateFormModel(model, schema); // символа нет\\n ```\\n\\n- **`applyWhen` не существует** — ни как экспорт, ни как локальный сахар: он эмитил branch-узел,\\n которого больше нет. Оборачивай условные правила оператором `validateWhen`.\\n\\n- **`ValidationSchemaFn` удалён** (тип старой path-схемы). Тип схемы — `ValidationSchema<T>`\\n (`(ctx: { model: FormModel<T> }) => void`), фабрика-обёртка — `defineValidationSchema<T>(fn)`.\\n\\n- **Cross-field — обычная функция над снапшотом, а не `ModelValidator (value, scope, root)`.**\\n Соседние поля читаются из снимка модели (`f: Root`, эквивалент `model.get()`), а правило навешивается\\n оператором `cross(sig, fn)`. Каноничное использование — `complex-multy-step-form/schemas/validation.ts`.\\n\\n ```typescript\\n import { cross } from \'@reformer/core/validation\';\\n import type { ValidationError } from \'@reformer/core\';\\n\\n // (f: Root) => error — сравнение с соседним полем, без scope/root-параметров\\n const passwordsMatch = (f: { password: string; confirmPassword: string }): ValidationError | null =>\\n f.confirmPassword && f.password && f.confirmPassword !== f.password\\n ? { code: \'mismatch\', message: \'Пароли не совпадают\' }\\n : null;\\n\\n // внутри defineValidationSchema — fn получает снапшот текущего scope (model.get()):\\n cross(model.$.confirmPassword, passwordsMatch);\\n ```"}],"examples":[],"troubleshooting":[],"seeAlso":["[03-api-signatures.md](./03-api-signatures.md) — сигнатуры `enableWhen`/`compute`/`copyFrom` (поведение) и `validate`/`validateWhen`/`cross`/`validateModel` (валидация)","[17-nonexistent-api.md](./17-nonexistent-api.md) — полный список удалённого API (`applyWhen`, `ValidationSchemaFn`, `validateFormModel`, …)","[25-reset-when.md](./25-reset-when.md) — `resetWhen` как альтернатива, когда поле остаётся enabled","[19-reading-values.md](./19-reading-values.md) — `useFormControlValue` и чтение значений в React"],"sections":[{"heading":"Purpose","slug":"purpose"},{"heading":"Видимость и доступность","slug":"vidimost-i-dostupnost"},{"heading":"Условная валидация","slug":"uslovnaya-validatsiya"},{"heading":"Скрытие в JSX","slug":"skrytie-v-jsx"},{"heading":"Anti-patterns удалённого контракта валидации","slug":"anti-patterns-udalennogo-kontrakta-validatsii"},{"heading":"See also","slug":"see-also-2"}],"terms":[["model",31],["enablewhen",12],["validatewhen",12],["when",11],["reformer",11],["core",11],["loantype",11],["только",9],["form",9],["поля",7],["при",7],["mortgage",7],["root",7],["валидация",6],["поле",6],["compute",6],["copyfrom",6],["definevalidationschema",6],["нет",6],["api",6],["import",6],["from",6],["null",6],["const",6],["schema",6],["validate",6],["cross",6],["required",6],["схемы",5],["validatemodel",5],["useformcontrolvalue",5],["validation",5],["children",5],["валидации",5],["resetondisable",5],["propertyvalue",5],["initialpayment",5],["доступность",4],["behaviors",4],["условная",4],["правила",4],["cond",4],["удалённого",4],["true",4],["значение",4],["typescript",4],["creditform",4],["boolean",4],["string",4],["field",4],["value",4],["как",4],["scope",4],["confirmpassword",4],["видимость",3],["под",3],["быть",3],["модели",3],["для",3],["значения",3],["оператор",3],["внутри",3],["скрытие",3],["jsx",3],["branch",3],["узла",3],["applywhen",3],["больше",3],["anti",3],["patterns",3],["контракта",3],["nonexistent",3],["условие",3],["без",3],["оператором",3],["validators",3],["тип",3],["чтобы",3],["return",3],["validateformmodel",3],["password",3],["условные",2],["если",2],["что",2],["именно",2],["должно",2],["остаётся",2],["раннером",2],["узел",2],["вообще",2],["условный",2],["реактивно",2],["его",2],["иначе",2],["сохраняется",2],["defineformbehavior",2],["type",2],["number",2],["sameemail",2],["email",2],["emailadditional",2],["или",2],["читает",2],["другого",2],["сигналы",2],["поведение",2],["через",2],["dsl",2],["cleanup",2],["сами",2],["когда",2],["group",2],["возвращает",2],["вариант",2],["условии",2],["ложном",2],["seterrors",2],["ошибки",2],["формы",2],["min",2],["ветка",2],["await",2],["ещё",2],["состояния",2],["раздела",2],["выше",2],["схема",2],["функция",2],["void",2],["validationschemafn",2],["get",2],["validationerror",2],["passwordsmatch",2],["signatures",2],["reset",2],["reading",2],["values",2]]},{"id":"reading-values","file":"19-reading-values.md","title":"reading-values","purpose":"Под M1 значения живут в модели. Есть три контекста чтения: value-доступ модели, сигналы, и React-хуки.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"16. READING FIELD VALUES (CRITICALLY IMPORTANT)","slug":"reading-field-values-critically-important"}],"terms":[["model",32],["address",12],["value",8],["email",8],["subscribe",6],["модели",5],["поля",5],["const",5],["city",5],["сигнал",5],["compute",5],["onchange",5],["значения",4],["сигналы",4],["typescript",4],["поле",4],["peek",4],["снимок",4],["field",3],["под",3],["доступ",3],["react",3],["control",3],["только",3],["модель",3],["внутри",3],["computed",3],["запись",3],["через",3],["нереактивный",3],["get",3],["для",3],["узел",3],["группы",3],["all",3],["addr",3],["amount",3],["term",3],["есть",2],["чтения",2],["хуки",2],["объект",2],["значение",2],["напрямую",2],["items",2],["effect",2],["читают",2],["реактивного",2],["дерева",2],["подписка",2],["целиком",2],["readonlysignal",2],["поэтому",2],["behaviors",2],["читаем",2],["defineformbehavior",2],["form",2]]},{"id":"compute-vs-watch","file":"20-compute-vs-watch.md","title":"compute-vs-watch","purpose":"Под M1 behaviors работают на сигналах модели. Есть два способа их писать:","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"17. COMPUTE vs ONCHANGE","slug":"compute-vs-onchange"}],"terms":[["model",36],["compute",16],["map",10],["onchange",9],["reformer",9],["core",9],["watchfield",8],["computefrom",7],["typescript",7],["только",6],["behaviors",5],["defineformbehavior",5],["примитив",5],["читай",5],["value",5],["proxy",5],["без",5],["cleanup",4],["для",4],["изменение",4],["async",4],["или",4],["import",4],["from",4],["const",4],["через",4],["array",4],["значения",4],["реакция",4],["debounce",4],["signal",4],["country",4],["сигналы",3],["dsl",3],["behavior",3],["target",3],["внутри",3],["поля",3],["пересчёт",3],["get",3],["field",3],["массива",3],["coborrowers",3],["элементов",3],["полей",3],["interestrate",3],["abortsignal",3],["поле",3],["любое",3],["работают",2],["модели",2],["есть",2],["писать",2],["массив",2],["side",2],["обновление",2],["componentprops",2],["auto",2],["tracking",2],["read",2],["цель",2],["нет",2],["peek",2],["myform",2],["level",2],["nested",2],["personaldata",2],["when",2],["это",2],["нереактивный",2],["зависимость",2],["отследится",2],["вне",2],["контекста",2],["сумма",2],["реактивно",2],["reduce",2],["читает",2],["трекает",2],["как",2],["length",2],["если",2],["нужен",2],["null",2],["явный",2],["источников",2],["monthlypayment",2],["amount",2],["term",2],["rate",2],["при",2],["form",2],["cities",2],["city",2],["группы",2],["address",2],["addr",2],["all",2],["формы",2],["производное",2]]},{"id":"array-operations","file":"21-array-operations.md","title":"array-operations","purpose":"Массивы объектов — model-owned. Мутации делаются через `ModelArray` (`model.arrayField`); рендер — через ноду формы (`form.items.map` / `.at`).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"18. ARRAY OPERATIONS","slug":"array-operations"}],"terms":[["model",22],["items",21],["item",17],["form",9],["array",7],["reformer",7],["name",6],["price",6],["core",6],["const",6],["typescript",5],["index",5],["import",5],["from",5],["row",5],["через",4],["map",4],["length",4],["myform",4],["return",4],["div",4],["button",4],["applyeach",4],["rows",4],["cross",4],["рендер",3],["формы",3],["formproxy",3],["push",3],["control",3],["remove",3],["add",3],["per",3],["defineformbehavior",3],["aggregateinto",3],["validation",3],["sum",3],["объектов",2],["modelarray",2],["ноду",2],["formmodel",2],["undefined",2],["плоские",2],["значения",2],["индексу",2],["removeat",2],["fieldconfig",2],["value",2],["component",2],["object",2],["usearraylength",2],["formfield",2],["onclick",2],["behavior",2],["compute",2],["behaviors",2],["others",2],["reduce",2],["percent",2],["sig",2],["скалярное",2],["поле",2],["носитель",2],["validationerror",2],["percentagessumto100",2],["null",2],["total",2]]},{"id":"cycle-detection","file":"22-cycle-detection.md","title":"Cycle Detection — предотвращение «Cycle detected»","purpose":"Behaviors на сигналах уже защищены от типичных циклов:","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Как устроено под M1","slug":"kak-ustroeno-pod-m1"},{"heading":"Когда всё-таки возникает «Cycle detected»","slug":"kogda-vse-taki-voznikaet-cycle-detected"},{"heading":"Prefer built-in operators over manual logic","slug":"prefer-built-in-operators-over-manual-logic"},{"heading":"Key Rules","slug":"key-rules"}],"terms":[["model",24],["compute",8],["enablewhen",8],["условие",7],["transformvalue",6],["typescript",6],["цель",5],["resetwhen",5],["prefix",5],["resetondisable",5],["cycle",4],["guard",4],["cardnumber",4],["detected",3],["если",3],["onchange",3],["или",3],["значения",3],["поля",3],["when",3],["true",3],["уже",2],["computefrom",2],["только",2],["значение",2],["peek",2],["запись",2],["вне",2],["effect",2],["контекста",2],["читает",2],["пишет",2],["можно",2],["перед",2],["disable",2],["это",2],["расходящийся",2],["взаимный",2],["условием",2],["field",2],["copyfrom",2],["собственную",2],["зависит",2],["через",2],["insurancetype",2],["casco",2]]},{"id":"copy-from","file":"23-copy-from.md","title":"copyFrom — Копирование значений между полями","purpose":"`copyFrom` декларативно копирует значение одного поля (или группы) в другое при выполнении условия `when`. Используется для UX-сценариев «совпадает с …»: «адрес проживания = адрес регистрации», «email для уведомлений = основной email», «billing = shipping». Оператор сам выходит из reactive-контекста (`runOutsideEffect`), поэтому не порождает «Cycle detected».","keyConcepts":[],"api":"Есть две формы. **Примитив из `@reformer/core`** (сигнал → сигнал):\\n\\n```typescript\\nfunction copyFrom<T>(\\n source: ReadonlySignal<T>,\\n target: Signal<T>,\\n options?: { when?: () => boolean; transform?: (value: T) => T }\\n): () => void; // возвращает cleanup\\n```\\n\\n**DSL-оператор из `@reformer/core/behaviors`** (сигнал ИЛИ группа):\\n\\n```typescript\\nfunction copyFrom<T>(\\n source: ReadonlySignal<T> | object, // model.$.field или model.$.group\\n target: Signal<T> | object,\\n options?: { when?: () => boolean; transform?: (value: T) => T }\\n): void; // cleanup управляется формой\\n```\\n\\n`when` — реактивное условие (читает сигналы модели через `model.*`). `transform` применяется\\nк значению перед записью в target. Отдельной опции `fields`/`debounce` нет.","patterns":[],"antiPatterns":[{"why":"Двусторонняя связь через два copyFrom — конфликт направлений","bad":"copyFrom(model.$.a, model.$.b);\\ncopyFrom(model.$.b, model.$.a);","correctNote":"Двусторонняя синхронизация — это работа syncFields","correct":"syncFields(model.$.a, model.$.b);"},{"why":"when, читающий саму target — лишний триггер при перезаписи target","bad":"copyFrom(model.$.source, model.$.target, { when: () => model.target === \'\' });","correctNote":"when опирается на независимый флаг","correct":"copyFrom(model.$.source, model.$.target, { when: () => model.copyEnabled === true });"}],"examples":[],"troubleshooting":[],"seeAlso":["[24-sync-fields.md](./24-sync-fields.md) — двусторонняя синхронизация","[25-reset-when.md](./25-reset-when.md) — сброс target при выключенном условии","[20-compute-vs-watch.md](./20-compute-vs-watch.md) — `compute` для производных значений","[22-cycle-detection.md](./22-cycle-detection.md) — почему `runOutsideEffect` защищает от циклов"],"sections":[{"heading":"Purpose","slug":"purpose-2"},{"heading":"API","slug":"api"},{"heading":"Examples","slug":"examples"},{"heading":"Anti-patterns","slug":"anti-patterns"},{"heading":"Troubleshooting","slug":"troubleshooting-2"},{"heading":"See also","slug":"see-also-3"}],"terms":[["model",36],["copyfrom",20],["when",20],["target",14],["typescript",8],["при",7],["source",7],["defineformbehavior",7],["reformer",6],["core",6],["value",6],["true",6],["email",5],["boolean",5],["transform",5],["string",5],["значение",4],["или",4],["группы",4],["для",4],["cycle",4],["behaviors",4],["import",4],["from",4],["const",4],["примитив",3],["сигнал",3],["fields",3],["синхронизация",3],["type",3],["useshippingasbilling",3],["shippingaddress",3],["billingaddress",3],["export",3],["registrationaddress",3],["sameemail",3],["emailadditional",3],["как",3],["двусторонняя",3],["reset",3],["compute",3],["копирование",2],["значений",2],["адрес",2],["оператор",2],["runoutsideeffect",2],["detected",2],["есть",2],["function",2],["readonlysignal",2],["signal",2],["options",2],["void",2],["возвращает",2],["cleanup",2],["object",2],["условие",2],["читает",2],["через",2],["orderform",2],["profileform",2],["sameasregistration",2],["address",2],["residenceaddress",2],["копировании",2],["contactform",2],["cleanups",2],["anti",2],["syncfields",2],["copyenabled",2],["behavior",2],["пишет",2],["sync",2],["watch",2],["detection",2]]},{"id":"sync-fields","file":"24-sync-fields.md","title":"syncFields — Двусторонняя синхронизация полей","purpose":"`syncFields` создаёт двунаправленную связь между двумя полями: изменение любого из них переписывает второе. Применяется для дублей одного значения в разных частях формы (тех. поле + видимое представление, mirror-поля). Внутренний флаг + `runOutsideEffect` исключают петли. Для одностороннего копирования — [`copyFrom`](./23-copy-from.md); для расчётов — [`compute`](./20-compute-vs-watch.md).","keyConcepts":[],"api":"Одинаково в примитиве (`@reformer/core`) и DSL (`@reformer/core/behaviors`):\\n\\n```typescript\\n// примитив: возвращает cleanup\\nfunction syncFields<T>(a: Signal<T>, b: Signal<T>, options?: { transform?: (value: T) => T }): () => void;\\n\\n// DSL: cleanup управляется формой\\nfunction syncFields<T>(a: Signal<T>, b: Signal<T>, options?: { transform?: (value: T) => T }): void;\\n```\\n\\n`a`/`b` — сигналы (`model.$.field`) совместимого типа `T`. `transform` **асимметричен**:\\nприменяется только при движении значения `a → b`. Опции `debounce`/`when` нет.","patterns":[],"antiPatterns":[{"why":"Симметрично через два copyFrom — конфликт направлений","bad":"copyFrom(model.$.a, model.$.b);\\ncopyFrom(model.$.b, model.$.a);","correctNote":"syncFields умеет двустороннюю связь без петель","correct":"syncFields(model.$.a, model.$.b);"},{"why":"Ожидание, что transform применится в обе стороны","bad":"syncFields(model.$.a, model.$.b, { transform: (v) => v.trim() });\\n// при записи в b значение НЕ trim-ается","correctNote":"Симметричные трансформы — syncFields + transformValue на обоих полях","correct":"syncFields(model.$.a, model.$.b);\\ntransformValue(model.$.a, (v) => (typeof v === \'string\' ? v.trim() : v));\\ntransformValue(model.$.b, (v) => (typeof v === \'string\' ? v.trim() : v));"},{"why":"Поля разного типа — рантайм-приведение и баги","bad":"syncFields(model.$.amountString, model.$.amountNumber); // string ↔ number","correctNote":"Для конвертации — compute в обе стороны или один канонический формат + computed отображение","correct":"compute(model.$.amountNumber, () => Number(model.amountString));"}],"examples":[],"troubleshooting":[],"seeAlso":["[23-copy-from.md](./23-copy-from.md) — однонаправленное копирование с `when`","[26-transform-value.md](./26-transform-value.md) — нормализация значений на месте","[22-cycle-detection.md](./22-cycle-detection.md) — почему симметричный copy ломается","[20-compute-vs-watch.md](./20-compute-vs-watch.md) — `compute` для производных значений"],"sections":[{"heading":"Purpose","slug":"purpose-3"},{"heading":"API","slug":"api-2"},{"heading":"Examples","slug":"examples-2"},{"heading":"Anti-patterns","slug":"anti-patterns-2"},{"heading":"Troubleshooting","slug":"troubleshooting-3"},{"heading":"See also","slug":"see-also-4"}],"terms":[["model",27],["syncfields",20],["transform",9],["compute",8],["value",8],["string",8],["copyfrom",7],["typescript",7],["from",6],["when",6],["для",5],["reformer",5],["core",5],["defineformbehavior",5],["поля",4],["copy",4],["signal",4],["при",4],["syncfield1",4],["syncfield2",4],["как",4],["trim",4],["transformvalue",4],["watch",3],["behaviors",3],["import",3],["const",3],["internalcode",3],["displaycode",3],["typeof",3],["через",3],["cycle",3],["полей",2],["связь",2],["применяется",2],["значения",2],["dsl",2],["примитив",2],["cleanup",2],["function",2],["options",2],["void",2],["типа",2],["только",2],["нет",2],["type",2],["mirrorform",2],["export",2],["нормализация",2],["записи",2],["displayform",2],["значение",2],["stop",2],["два",2],["что",2],["обе",2],["стороны",2],["amountstring",2],["amountnumber",2],["number",2],["условием",2],["значений",2],["detection",2]]},{"id":"reset-when","file":"25-reset-when.md","title":"resetWhen — Условный сброс полей","purpose":"`resetWhen` сбрасывает значение поля к `resetValue`, когда `condition` истинно. Это альтернатива `enableWhen({ resetOnDisable: true })`, когда поле остаётся **enabled**, но содержимое нужно очистить (например, переключение способа оплаты обнуляет «номер карты», но поле по-прежнему доступно). По умолчанию пишет `null`; `resetValue` задаёт произвольное значение.","keyConcepts":[],"api":"Одинаково в примитиве (`@reformer/core`) и DSL (`@reformer/core/behaviors`):\\n\\n```typescript\\n// примитив: возвращает cleanup\\nfunction resetWhen<T>(target: Signal<T>, condition: () => boolean, options?: { resetValue?: T }): () => void;\\n\\n// DSL: cleanup управляется формой\\nfunction resetWhen<T>(target: Signal<T>, condition: () => boolean, options?: { resetValue?: T }): void;\\n```\\n\\n`target` — сигнал (`model.$.field`). `condition` — реактивное условие (читает `model.*`).\\n`resetValue` по умолчанию `null`. Опций `onlyIfDirty`/`debounce` нет; флаги dirty/touched\\nполя не трогаются оператором (значения принадлежат модели).","patterns":[],"antiPatterns":[{"why":"resetWhen вместо enableWhen для disable-сценария","bad":"resetWhen(model.$.field, () => !model.show);\\n// поле останется enabled и валидируемым — ошибка required всё равно прилетит","correctNote":"Если поле должно «исчезнуть» — блокируем + сбрасываем","correct":"enableWhen(model.$.field, () => model.show, { resetOnDisable: true });"},{"why":"resetValue с типом, отличным от поля","bad":"resetWhen(model.$.amount, () => model.skipPayment, { resetValue: \'none\' }); // amount: number ← string","correctNote":"resetValue совместим с типом поля","correct":"resetWhen(model.$.amount, () => model.skipPayment, { resetValue: 0 });"},{"why":"Для строкового поля без resetValue прилетит null, а Input ждёт string","bad":"resetWhen(model.$.cardNumber, () => model.paymentType !== \'card\');","correctNote":"Явный resetValue для строк","correct":"resetWhen(model.$.cardNumber, () => model.paymentType !== \'card\', { resetValue: \'\' });"},{"why":"condition читает саму цель — самотриггер (см. 22-cycle-detection.md)","bad":"resetWhen(model.$.cardNumber, () => model.cardNumber !== \'\');","correctNote":"condition зависит только от независимого поля","correct":"resetWhen(model.$.cardNumber, () => model.paymentType !== \'card\', { resetValue: \'\' });"}],"examples":[],"troubleshooting":[],"seeAlso":["[04-common-patterns.md](./04-common-patterns.md) — `enableWhen({ resetOnDisable: true })` как альтернатива","[23-copy-from.md](./23-copy-from.md) — копирование, у которого нет встроенного отката","[22-cycle-detection.md](./22-cycle-detection.md) — почему `condition` не должен читать целевое поле"],"sections":[{"heading":"Purpose","slug":"purpose-4"},{"heading":"API","slug":"api-3"},{"heading":"Examples","slug":"examples-3"},{"heading":"Anti-patterns","slug":"anti-patterns-3"},{"heading":"Troubleshooting","slug":"troubleshooting-4"},{"heading":"See also","slug":"see-also-5"}],"terms":[["model",31],["resetwhen",22],["resetvalue",18],["condition",10],["cardnumber",9],["поля",8],["typescript",8],["paymenttype",7],["card",7],["для",6],["enablewhen",5],["true",5],["поле",5],["reformer",5],["core",5],["defineformbehavior",5],["from",5],["resetondisable",4],["null",4],["сброс",3],["behaviors",3],["примитив",3],["target",3],["field",3],["читает",3],["import",3],["string",3],["const",3],["propertyvalue",3],["number",3],["initialpayment",3],["patterns",3],["amount",3],["cycle",3],["detection",3],["что",3],["полей",2],["значение",2],["когда",2],["альтернатива",2],["enabled",2],["способа",2],["оплаты",2],["карты",2],["умолчанию",2],["dsl",2],["возвращает",2],["cleanup",2],["function",2],["signal",2],["boolean",2],["options",2],["void",2],["нет",2],["значения",2],["type",2],["checkoutform",2],["export",2],["mortgageform",2],["без",2],["сбрасываем",2],["как",2],["show",2],["прилетит",2],["типом",2],["skippayment",2],["зависит",2],["behavior",2],["или",2],["сброса",2],["common",2],["copy",2]]},{"id":"transform-value","file":"26-transform-value.md","title":"transformValue — Автоматическая трансформация значений","purpose":"`transformValue` подписывается на изменение поля и переписывает его трансформированной версией: uppercase для кодов, trim+toLowerCase для email, округление для чисел. Применяется единообразно ко всем источникам изменения (пользователь, `model.field = …`, `model.set/patch`, `copyFrom`). **Идемпотентность (`f(f(x)) === f(x)`) обязательна** — иначе бесконечный цикл. Оператор откладывает запись вне effect-контекста (`runOutsideEffect`) и не пишет, если `transformer(value) === value` — базовый guard от циклов.","keyConcepts":[],"api":"Одинаково в примитиве (`@reformer/core`) и DSL (`@reformer/core/behaviors`):\\n\\n```typescript\\n// примитив: возвращает cleanup\\nfunction transformValue<T>(target: Signal<T>, transformer: (value: T) => T): () => void;\\n\\n// DSL: cleanup управляется формой\\nfunction transformValue<T>(target: Signal<T>, transformer: (value: T) => T): void;\\n```\\n\\n`target` — сигнал (`model.$.field`). `transformer` — чистая идемпотентная функция значения.\\nДополнительных опций (`debounce`, `onUserChangeOnly`, `emitEvent`) и готового набора\\n`transformers`/`createTransformer` НЕТ — трансформер пишется как обычная функция.","patterns":[],"antiPatterns":[{"why":"Неидемпотентный transformer — бесконечный цикл","bad":"transformValue(model.$.field, (v) => `prefix-${v}`); // f(f(x)) ≠ f(x)","correctNote":"Guard внутри transformer","correct":"transformValue(model.$.field, (v) => (v?.startsWith(\'prefix-\') ? v : `prefix-${v}`));"},{"why":"transformValue ОДНОВРЕМЕННО с syncFields на том же поле","bad":"syncFields(model.$.a, model.$.b);\\ntransformValue(model.$.b, (v) => v.toUpperCase()); // взаимные перезаписи","correctNote":"Трансформируй источник ДО синхронизации","correct":"transformValue(model.$.a, (v) => v.toUpperCase());\\nsyncFields(model.$.a, model.$.b);"},{"why":"transformValue для производных полей (нет доступа к другим полям)","bad":"transformValue(model.$.fullName, () => `${model.firstName} ${model.lastName}`);","correctNote":"Для зависимостей от других полей — compute","correct":"compute(model.$.fullName, () => `${model.firstName} ${model.lastName}`);"}],"examples":[],"troubleshooting":[],"seeAlso":["[24-sync-fields.md](./24-sync-fields.md) — порядок применения с syncFields","[23-copy-from.md](./23-copy-from.md) — `transform`-опция при копировании","[22-cycle-detection.md](./22-cycle-detection.md) — про идемпотентность","[16-ui-components.md](./16-ui-components.md) — `<InputMask>` для тяжёлого форматирования"],"sections":[{"heading":"Purpose","slug":"purpose-5"},{"heading":"API","slug":"api-4"},{"heading":"Examples","slug":"examples-4"},{"heading":"Anti-patterns","slug":"anti-patterns-4"},{"heading":"Troubleshooting","slug":"troubleshooting-5"},{"heading":"See also","slug":"see-also-6"}],"terms":[["model",27],["transformvalue",24],["value",17],["transformer",10],["typescript",8],["для",7],["target",7],["trim",6],["reformer",6],["const",6],["touppercase",6],["digits",6],["core",5],["defineformbehavior",5],["from",5],["string",5],["email",4],["field",4],["signal",4],["slice",4],["syncfields",4],["behaviors",3],["примитив",3],["нет",3],["import",3],["uppercasefield",3],["return",3],["prefix",3],["cycle",3],["при",3],["трансформация",2],["uppercase",2],["tolowercase",2],["округление",2],["применяется",2],["идемпотентность",2],["бесконечный",2],["цикл",2],["вне",2],["базовый",2],["guard",2],["dsl",2],["cleanup",2],["function",2],["void",2],["функция",2],["готового",2],["набора",2],["как",2],["type",2],["promoform",2],["export",2],["contactform",2],["phone",2],["amount",2],["number",2],["телефон",2],["promocode",2],["toupper",2],["неидемпотентный",2],["полей",2],["fullname",2],["firstname",2],["lastname",2],["compute",2],["проверь",2],["что",2],["behavior",2],["inputmask",2],["sync",2],["fields",2],["copy",2],["detection",2],["components",2]]},{"id":"revalidate-when","file":"27-revalidate-when.md","title":"revalidateWhen — Перевалидация по триггерам","purpose":"`revalidateWhen` вызывает переданный колбэк ревалидации, когда изменяется любая из зависимостей. Применяется, когда правило зависит от значений других полей (`amount <= maxAmount`, `confirmPassword === password`, `initialPayment >= propertyValue * 0.2`). Валидация — отдельная функция-схема (`@reformer/core/validation`), прогоняемая по требованию через `validateModel(model, schema)`. Поэтому ревалидация выражается явным колбэком, а не автоматической привязкой к полю: поведение (`revalidateWhen`) лишь _инициирует_ прогон схемы валидации при изменении зависимости.","keyConcepts":[],"api":"`revalidateWhen` — оператор поведения (`@reformer/core/behaviors`, либо примитив `@reformer/core`).\\nЕго сигнатура НЕ зависит от контракта валидации:\\n\\n```typescript\\n// примитив: возвращает cleanup\\nfunction revalidateWhen(deps: ReadonlySignal<unknown>[], revalidate: () => void): () => void;\\n\\n// DSL: cleanup управляется формой\\nfunction revalidateWhen(deps: ReadonlySignal<unknown>[], revalidate: () => void): void;\\n```\\n\\n`deps` — массив сигналов-триггеров (`model.$.field`). `revalidate` — колбэк (обычно\\n`() => void validateModel(model, schema)`, где `schema` — `defineValidationSchema<T>(({ model }) => …)`).\\nВызывается при изменении любой зависимости (НЕ на инициализации), вне effect-контекста.","patterns":[],"antiPatterns":[{"why":"Триггер == поле, которое и так меняется само","bad":"revalidateWhen([model.$.amount], () => validateModel(model, schema));\\n// amount и так валидируется при собственном изменении в общем прогоне","correctNote":"Триггеры — ДРУГИЕ поля, от которых зависит правило amount","correct":"revalidateWhen([model.$.maxAmount, model.$.discount], () => validateModel(model, schema));"},{"why":"Правило только через revalidateWhen, но в схеме нет зависимости от триггера","bad":"revalidateWhen([model.$.maxAmount], () => validateModel(model, schema));\\n// а валидатор amount — статичный max(1000), не читает maxAmount","correctNote":"Сначала cross-field правило (читает снапшот формы) в схеме валидации, потом revalidateWhen","correct":"const amountVsMax = (f: Form): ValidationError | null =>\\n f.amount != null && f.maxAmount != null && f.amount > f.maxAmount\\n ? { code: \'tooBig\', message: \'...\' }\\n : null;\\n\\nconst schema = defineValidationSchema<Form>(({ model }) => {\\n cross(model.$.amount, amountVsMax); // навешиваем правило на поле amount\\n});\\nrevalidateWhen([model.$.maxAmount], () => void validateModel(model, schema));"}],"examples":[],"troubleshooting":[],"seeAlso":["[03-api-signatures.md](./03-api-signatures.md) — cross-field `cross(sig, fn)` и раннер `validateModel`","[28-submit-and-reset.md](./28-submit-and-reset.md) — полная валидация формы","[20-compute-vs-watch.md](./20-compute-vs-watch.md) — реактивные производные значения"],"sections":[{"heading":"Purpose","slug":"purpose-6"},{"heading":"API","slug":"api-5"},{"heading":"Examples","slug":"examples-5"},{"heading":"Anti-patterns","slug":"anti-patterns-5"},{"heading":"Troubleshooting","slug":"troubleshooting-6"},{"heading":"See also","slug":"see-also-7"}],"terms":[["model",37],["revalidatewhen",21],["validatemodel",19],["amount",13],["maxamount",11],["reformer",11],["core",11],["void",11],["schema",10],["cross",10],["правило",8],["import",8],["from",8],["const",8],["typescript",7],["defineformbehavior",7],["validation",5],["при",5],["field",5],["где",5],["зависит",4],["через",4],["api",4],["behaviors",4],["deps",4],["amountvsmax",4],["читает",4],["формы",4],["только",4],["null",4],["перевалидация",3],["колбэк",3],["confirmpassword",3],["password",3],["propertyvalue",3],["схема",3],["валидации",3],["изменении",3],["зависимости",3],["примитив",3],["revalidate",3],["definevalidationschema",3],["export",3],["paymentschema",3],["схеме",3],["снапшот",3],["signatures",3],["схему",3],["поле",3],["триггера",3],["form",3],["sig",3],["вызывает",2],["когда",2],["полей",2],["initialpayment",2],["валидация",2],["функция",2],["поэтому",2],["cleanup",2],["function",2],["readonlysignal",2],["unknown",2],["триггеров",2],["вне",2],["смене",2],["для",2],["loanamount",2],["passwordsmatch",2],["как",2],["так",2],["поля",2],["ошибки",2],["onefieldschema",2],["раннер",2],["submit",2],["and",2],["reset",2],["compute",2],["watch",2]]},{"id":"submit-and-reset","file":"28-submit-and-reset.md","title":"Submit и Reset — Жизненный цикл отправки формы","purpose":"Канонический submit-флоу под M1: «запустить полную валидацию данных (`validateModel`) → проверить `boolean`-результат → достать снимок (`model.get()`) → сделать запрос → `model.reset()`». Валидация — **отдельный слой** (`@reformer/core/validation`, схема через `defineValidationSchema`), она НЕ входит в layout-дерево, которое получает `createForm`. Раннер `validateModel(model, schema)` сам роутит ошибки в ноды формы, поэтому UI подсветит проблемные поля, а наружу вернёт лишь `boolean` (false = есть блокирующая ошибка; `severity:\'warning\'` показывается, но submit не блокирует). `model.reset()` возвращает значения к initial-снимку.","keyConcepts":[],"api":"```typescript\\n// Модель (источник истины значений):\\ninterface ModelApi<T> {\\n get(): T; // снимок значений — для submit\\n set(value: T): void; // полная установка (все ключи T)\\n patch(value: Partial<T>): void; // частичное слияние\\n isDirty(): boolean; // отличаются ли значения от initial-снимка\\n reset(): void; // вернуть к initial-снимку\\n captureInitial(): void; // зафиксировать текущие как новый initial\\n}\\n\\n// Валидация данных — headless-раннер: находит ноды по сигналам модели, роутит в них ошибки,\\n// отменяет устаревшие прогоны той же (model, schema). Возвращает ТОЛЬКО boolean:\\nvalidateModel<T>(model: FormModel<T>, schema: ValidationSchema<T>): Promise<boolean>\\n// true = нет блокирующих ошибок (severity:\'warning\' не блокирует, но показывается).\\n// false = есть блокирующая ошибка; она уже проставлена в ноду → UI подсветит поле.\\n\\n// Схема валидации — отдельный слой над моделью (не смешивается с layout):\\ndefineValidationSchema<T>(({ model }) => {\\n validate(model.$.field, [rules]); // синхронные правила поля\\n // validateAsync / validateWhen / cross / each / apply — см. contract-spec\\n}): ValidationSchema<T>\\n\\n// Нода поля/формы (для точечной работы с UI-состоянием):\\nform.markAsTouched(); // тронуть все поля (показать ошибки)\\nform.clearErrors(); // снять ошибки со всех нод\\nform.<field>.setErrors([{ code, message }]); // серверная/бизнес-ошибка в конкретное поле\\nform.<field>.clearErrors();\\n```","patterns":[],"antiPatterns":[{"why":"Обращение к .valid: раннер возвращает boolean, а не { valid, errors }","bad":"const result = await validateModel(model, schema);\\nif (!result.valid) return; // result — boolean, .valid === undefined → guard никогда не сработает","correctNote":"Результат — сам boolean","correct":"const valid = await validateModel(model, schema);\\nif (!valid) return;"},{"why":"Чтение результата валидации без await — сабмитим по неполному вердикту","bad":"const handleSubmit = (e) => {\\n e.preventDefault();\\n validateModel(model, schema); // Promise проигнорирован, async-валидаторы не дождались\\n submit(model.get());\\n};","correctNote":"Дождаться и проверить boolean","correct":"const handleSubmit = async (e) => {\\n e.preventDefault();\\n if (await validateModel(model, schema)) submit(model.get());\\n};"},{"why":"Валидаторы в layout-дереве, отдаваемом в createForm — layout не несёт правил","bad":"createForm({ model, schema: { username: { value: \'\', validators: [required()] } } });","correctNote":"Валидация — отдельная схема, прогоняется раннером","correct":"const schema = defineValidationSchema<T>(({ model }) => {\\n validate(model.$.username, [required()]);\\n});\\nawait validateModel(model, schema);"},{"why":"model.reset() до ответа сервера — потеря данных при ошибке","bad":"await api.send(model.get());\\nmodel.reset();","correctNote":"Reset только после успеха","correct":"try {\\n await api.send(model.get());\\n model.reset();\\n} catch (err) { showError(err); }"},{"why":"Сброс полей по очереди — многословно","bad":"model.username = \'\';\\nmodel.email = \'\';\\nmodel.password = \'\';","correctNote":"model.reset() — к initial-снимку одним вызовом","correct":"model.reset();"}],"examples":[],"troubleshooting":[],"seeAlso":["[29-async-preload.md](./29-async-preload.md) — initial values и preload через `set`/`patch`","[13-multi-step.md](./13-multi-step.md) — пошаговая валидация через `validateModel` (`validateStep`/`validateAll`)","[27-revalidate-when.md](./27-revalidate-when.md) — мост «поведение → валидация»: `revalidateWhen([deps], () => void validateModel(model, schema))`","[03-api-signatures.md](./03-api-signatures.md) — сигнатуры модели и `validateModel`","[05-common-mistakes.md](./05-common-mistakes.md) — типичные ошибки"],"sections":[{"heading":"Purpose","slug":"purpose-7"},{"heading":"API","slug":"api-6"},{"heading":"Examples","slug":"examples-6"},{"heading":"Anti-patterns","slug":"anti-patterns-6"},{"heading":"Troubleshooting","slug":"troubleshooting-7"},{"heading":"See also","slug":"see-also-8"}],"terms":[["model",55],["validatemodel",21],["const",21],["reset",19],["form",16],["schema",14],["submit",12],["valid",12],["await",12],["get",11],["ошибки",11],["boolean",10],["return",10],["initial",9],["email",9],["username",9],["button",8],["валидация",7],["поля",7],["ошибка",7],["api",7],["typescript",7],["message",7],["password",7],["async",7],["данных",6],["reformer",6],["core",6],["layout",6],["createform",6],["возвращает",6],["значения",6],["validate",6],["import",6],["from",6],["required",6],["после",6],["definevalidationschema",5],["раннер",5],["void",5],["только",5],["true",5],["поле",5],["createmodel",5],["type",5],["handlesubmit",5],["response",5],["схема",4],["ноды",4],["severity",4],["warning",4],["снимку",4],["patch",4],["field",4],["clearerrors",4],["react",4],["registrationformdata",4],["чтобы",4],["function",4],["без",4],["preventdefault",4],["error",4],["формы",3],["validation",3],["через",3],["роутит",3],["подсветит",3],["false",3],["показывается",3],["блокирует",3],["set",3],["value",3],["модели",3],["валидации",3],["моделью",3],["markastouched",3],["всех",3],["tsx",3],["minlength",3],["string",3],["registrationschema",3],["шаг",3],["данные",3],["formfield",3],["control",3],["testid",3],["очистить",3],["result",3],["при",3],["preload",3],["проверить",2],["результат",2],["достать",2],["снимок",2],["сделать",2],["отдельный",2],["слой",2],["она",2],["входит",2],["дерево",2],["получает",2],["сам",2],["поэтому",2],["есть",2],["блокирующая",2],["модель",2],["значений",2],["для",2],["все",2],["partial",2],["isdirty",2],["captureinitial",2],["headless",2],["находит",2],["сигналам",2],["них",2],["устаревшие",2],["прогоны",2],["formmodel",2],["validationschema",2],["promise",2],["над",2],["показать",2],["нод",2],["seterrors",2],["code",2],["серверная",2],["бизнес",2],["usememo",2],["validators",2],["отдельная",2],["обязателен",2],["пароль",2],["formevent",2],["отправить",2],["payload",2],["register",2],["json",2],["успеха",2],["try",2],["форму",2],["catch",2],["handlereset",2],["clearjustpassword",2],["сброс",2],["onclick",2],["вне",2],["rawdata",2],["myform",2],["валидаторы",2],["сервера",2],["send",2],["err",2],["полей",2],["вернул",2],["загруженные",2],["multi",2],["step",2],["revalidate",2],["when",2],["signatures",2],["common",2],["mistakes",2]]},{"id":"async-preload","file":"29-async-preload.md","title":"Async Preload — Загрузка начальных значений и справочников","purpose":"Загрузка формы данными с сервера под M1: (1) **initial values** в `createModel(...)`; (2) **`model.set` / `model.patch`** для загрузки/обновления значений; (3) **external React-hook** для full-blown async preload (параллельный fetch заявки + справочников, обработка ошибок, race-guard через deps). Динамические `componentProps` (опции селектов) обновляются через `form.field.updateComponentProps({ options })` в `queueMicrotask`, чтобы не пересечься с реактивными эффектами от `set`/`patch`.","keyConcepts":[],"api":"```typescript\\n// Модель:\\nmodel.set(value: T): void; // полная установка значений (load полного DTO). Не меняет initial.\\nmodel.patch(value: Partial<T>): void; // частичное слияние (только переданные ключи). Не меняет initial.\\nmodel.reset(): void; // вернуть к initial-снимку\\nmodel.captureInitial(): void; // сделать текущие значения новым initial-снимком\\n\\n// Нода поля/группы:\\nform.field.updateComponentProps(props: Record<string, unknown>): void; // динамические опции и т.п.\\n```\\n\\nInitial values задаются в `createModel(initial)`; `reset()` возвращает к ним. Чтобы загруженные\\nданные стали новой «точкой отсчёта» для `reset()` — вызови `model.captureInitial()` после load.","patterns":[],"antiPatterns":[{"why":"model/form пересоздаются на каждый рендер → preload запускается каждый раз","bad":"function MyForm() {\\n const model = createModel<T>(initial); // КАЖДЫЙ рендер!\\n const form = createForm({ model, schema });\\n}","correctNote":"Стабильные ссылки через useMemo","correct":"function MyForm() {\\n const { model, form } = useMemo(() => {\\n const m = createModel<T>(initial);\\n return { model: m, form: createForm({ model: m, schema: buildSchema(m) }) };\\n }, []);\\n}"},{"why":"updateComponentProps синхронно после set → возможный конфликт с реактивными эффектами","bad":"model.set(data);\\nform.region.updateComponentProps({ options: [...] });","correctNote":"queueMicrotask, чтобы реактивные эффекты от set завершились","correct":"model.set(data);\\nqueueMicrotask(() => form.region.updateComponentProps({ options: [...] }));"},{"why":"Нет race-guard в async useEffect","bad":"useEffect(() => { fetchData(id).then((d) => model.set(d)); }, [id]);","correctNote":"Cleanup-флаг","correct":"useEffect(() => {\\n let cancelled = false;\\n fetchData(id).then((d) => { if (!cancelled) model.set(d); });\\n return () => { cancelled = true; };\\n}, [id]);"}],"examples":[],"troubleshooting":[],"seeAlso":["[28-submit-and-reset.md](./28-submit-and-reset.md) — обратная сторона жизненного цикла","[11-async-watchfield.md](./11-async-watchfield.md) — `onChange` для динамики после preload","[22-cycle-detection.md](./22-cycle-detection.md) — почему `queueMicrotask` нужен","[16-ui-components.md](./16-ui-components.md) — `updateComponentProps` для динамических опций"],"sections":[{"heading":"Purpose","slug":"purpose-8"},{"heading":"API","slug":"api-7"},{"heading":"Examples","slug":"examples-7"},{"heading":"Anti-patterns","slug":"anti-patterns-7"},{"heading":"Troubleshooting","slug":"troubleshooting-8"},{"heading":"See also","slug":"see-also-9"}],"terms":[["model",32],["form",17],["set",16],["initial",11],["updatecomponentprops",11],["const",11],["после",10],["через",9],["return",9],["async",8],["options",8],["reset",8],["error",8],["cancelled",8],["preload",7],["createmodel",7],["queuemicrotask",7],["value",7],["для",6],["typescript",6],["username",6],["isloading",6],["null",6],["applicationid",6],["region",6],["patch",5],["componentprops",5],["void",5],["import",5],["from",5],["reformer",5],["language",5],["marketing",5],["true",5],["schema",5],["useeffect",5],["setstate",5],["false",5],["onchange",5],["загрузка",4],["значений",4],["чтобы",4],["string",4],["createform",4],["core",4],["label",4],["data",4],["city",4],["каждый",4],["сервера",3],["values",3],["race",3],["guard",3],["динамические",3],["опции",3],["captureinitial",3],["возвращает",3],["вызови",3],["inputfield",3],["type",3],["component",3],["loadingstate",3],["function",3],["appresp",3],["dictsresp",3],["await",3],["cities",3],["err",3],["usememo",3],["справочников",2],["загрузки",2],["external",2],["react",2],["hook",2],["field",2],["реактивными",2],["эффектами",2],["модель",2],["load",2],["меняет",2],["снимку",2],["поля",2],["данные",2],["отсчёта",2],["selectfield",2],["profileform",2],["boolean",2],["usestate",2],["formmodel",2],["formproxy",2],["export",2],["creditapplicationform",2],["state",2],["let",2],["try",2],["status",2],["catch",2],["при",2],["defineformbehavior",2],["signal",2],["рендер",2],["myform",2],["fetchdata",2],["then",2],["submit",2],["and",2],["watchfield",2],["cycle",2],["detection",2],["components",2]]},{"id":"type-safety-recipes","file":"30-type-safety-recipes.md","title":"type-safety-recipes","purpose":"Идиоматичные паттерны, которые держат сгенерированный код без `any` и `as`-кастов под M1.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"30. TYPE-SAFETY RECIPES","slug":"type-safety-recipes"}],"terms":[["model",23],["type",16],["reformer",15],["core",15],["null",13],["recipe",10],["typescript",8],["import",8],["from",8],["value",8],["loanamount",7],["const",7],["behaviors",6],["validation",6],["compute",6],["string",5],["creditapplicationform",5],["field",5],["без",4],["типы",4],["схема",4],["definevalidationschema",4],["cross",4],["rule",4],["min",4],["поля",4],["personaldata",4],["полей",4],["для",4],["control",4],["fieldnode",4],["модель",3],["defineformbehavior",3],["validate",3],["form",3],["interface",3],["export",3],["propertyitem",3],["number",3],["properties",3],["модели",3],["правила",3],["validationerror",3],["initialpayment",3],["внутри",3],["напрямую",3],["root",2],["операторы",2],["validatemodel",2],["валидаторов",2],["validators",2],["createmodel",2],["formproxy",2],["modelsignals",2],["required",2],["max",2],["onchange",2],["примитив",2],["shape",2],["это",2],["array",2],["item",2],["выводятся",2],["валидаторы",2],["над",2],["снапшотом",2],["поле",2],["initialpaymentvsproperty",2],["propertyvalue",2],["code",2],["message",2],["читает",2],["касты",2],["minlength",2],["minage",2],["birthdate",2],["useformcontrol",2],["используй",2],["myfieldprops",2],["именованные",2],["validateadultage",2],["return",2],["age",2],["new",2],["date",2],["getfullyear",2],["myform",2]]},{"id":"async-validator-debounce","file":"31-async-validator-debounce.md","title":"async-validator-debounce","purpose":"Для проверок типа «уникальность email», «валидация ИНН через API», «проверка адреса» — async-правило это `AsyncRule<T>` = `(value, { signal }) => Promise<ValidationError | null>`. Оно регистрируется оператором `validateAsync(sig, [asyncRules])` внутри схемы валидации (`@reformer/core/validation`) и исполняется внешним раннером `validateModel` (async-правила прогоняются параллельно через `Promise.all`, раннер их дожидается).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[27-revalidate-when.md](27-revalidate-when.md) — перезапуск `validateModel` по триггерам","[29-async-preload.md](29-async-preload.md) — async preload данных при init формы","[32-async-options-loading.md](32-async-options-loading.md) — `onChange` с debounce + AbortSignal"],"sections":[{"heading":"31. ASYNC VALIDATOR","slug":"async-validator"}],"terms":[["async",23],["model",19],["email",16],["validatemodel",12],["const",12],["validateasync",10],["signal",9],["null",9],["await",9],["promise",8],["sync",8],["value",7],["правила",7],["return",7],["schema",7],["debounce",7],["через",6],["reformer",6],["core",6],["правило",5],["import",5],["from",5],["validate",5],["required",5],["boolean",5],["submit",5],["api",4],["asyncrule",4],["sig",4],["раннер",4],["definevalidationschema",4],["abortsignal",4],["fetch",4],["string",4],["res",4],["отмена",4],["прогон",4],["onchange",4],["username",4],["для",3],["это",3],["схемы",3],["validation",3],["json",3],["available",3],["cross",3],["seterrors",3],["возвращает",3],["нет",3],["false",3],["держи",3],["setchecking",3],["errors",3],["preload",3],["валидация",2],["validationerror",2],["оператором",2],["asyncrules",2],["валидации",2],["исполняется",2],["раннером",2],["параллельно",2],["all",2],["дожидается",2],["схема",2],["createmodel",2],["его",2],["flight",2],["checkemailunique",2],["try",2],["check",2],["code",2],["message",2],["сетевой",2],["блокирует",2],["разными",2],["операторами",2],["одном",2],["сигнале",2],["шаг",2],["как",2],["ambient",2],["прогоняет",2],["схему",2],["полей",2],["ошибки",2],["формы",2],["true",2],["если",2],["инлайн",2],["формат",2],["inn",2],["field",2],["pending",2],["только",2],["поэтому",2],["обычно",2],["checking",2],["нужен",2],["revalidatewhen",2],["defineformbehavior",2],["void",2],["снапшот",2],["get",2],["revalidate",2],["when",2],["options",2],["loading",2]]},{"id":"async-options-loading","file":"32-async-options-loading.md","title":"async-options-loading","purpose":"Для динамической подгрузки опций dropdown\'а по значению другого поля (`region` → `city options`, `carBrand` → `carModel options`) — используй `onChange` из `@reformer/core/behaviors` + `form.field.updateComponentProps({ options })`. `onChange` даёт debounce и AbortSignal из коробки.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[11-async-watchfield.md](11-async-watchfield.md) — общий паттерн `onChange`","[29-async-preload.md](29-async-preload.md) — preload данных при инициализации","[31-async-validator-debounce.md](31-async-validator-debounce.md) — async **валидация** (не options)"],"sections":[{"heading":"32. ASYNC OPTIONS LOADING","slug":"async-options-loading"}],"terms":[["options",16],["async",14],["updatecomponentprops",12],["onchange",11],["signal",11],["region",10],["debounce",9],["form",8],["loading",7],["city",7],["model",7],["target",7],["value",6],["registrationaddress",6],["preload",6],["const",5],["при",5],["reformer",4],["core",4],["behaviors",4],["abortsignal",4],["string",4],["fetch",4],["return",4],["source",4],["true",4],["false",4],["resettarget",4],["для",3],["import",3],["from",3],["fetchcitiesbyregion",3],["opts",3],["await",3],["поле",3],["смене",3],["устаревший",3],["tvalue",3],["void",3],["reset",3],["опций",2],["carbrand",2],["carmodel",2],["даёт",2],["defineformbehavior",2],["type",2],["cityoption",2],["function",2],["promise",2],["res",2],["зависимое",2],["try",2],["catch",2],["aborterror",2],["запрос",2],["оператор",2],["readonlysignal",2],["loadoptionson",2],["toption",2],["fetcher",2],["data",2],["инициализации",2],["immediate",2],["watchfield",2],["validator",2]]},{"id":"validation-strategy","file":"33-validation-strategy.md","title":"useFormValidation — Единый выбор стратегии валидации","purpose":"Одна декларативная точка выбора «когда прогонять схему валидации» вместо ручной разводки `markAsTouched` + `validateModel` + `revalidateWhen` + `useState(pending)`. Аддитивный слой над функциональной схемой (`@reformer/core/validation`): переиспользует `validateModel` как ЕДИНСТВЕННЫЙ движок (роутинг ошибок в ноды, отмена устаревших прогонов, дедуп по `(model, schema)`), второго движка не заводит. Node-level `updateOn` / `debounce` на самой ноде поля (legacy-триггеры) этот API НЕ трогает.","keyConcepts":[],"api":"Основной способ — React-хук `useFormValidation` из `@reformer/core` (рядом с `useFormControl`).\\nПод ним — headless-фабрика `createFormValidation` из `@reformer/core/validation` (для SSR / тестов /\\nне-React потребителей).\\n\\n```typescript\\n// React (@reformer/core)\\nfunction useFormValidation<T>(args: {\\n model: FormModel<T>;\\n schema: ValidationSchema<T>; // СТАБИЛЬНАЯ ссылка (module-level const / useMemo)\\n strategy?: ValidationStrategyKind; // default \'submit\'\\n debounce?: number; // мс, для live-фаз (change / live-часть afterFirstSubmit)\\n liveAfterSubmit?: \'change\' | \'blur\'; // default \'change\'\\n}): { submit: () => Promise<boolean>; validate: () => Promise<boolean>; isValidating: boolean };\\n\\n// headless (@reformer/core/validation)\\ntype ValidationStrategyKind = \'submit\' | \'blur\' | \'change\' | \'afterFirstSubmit\';\\ninterface ValidationStrategyOptions {\\n strategy?: ValidationStrategyKind;\\n debounce?: number;\\n liveAfterSubmit?: \'change\' | \'blur\';\\n}\\ninterface FormValidationController {\\n validate(): Promise<boolean>; // полный прогон, touch:true (раскрыть ВСЕ ошибки); переводит afterFirstSubmit в live-фазу\\n start(): () => void; // армит реактивные подписки (ТОЛЬКО на клиенте) → dispose\\n dispose(): void;\\n readonly isValidating: boolean;\\n readonly validating: ReadonlySignal<boolean>;\\n}\\nfunction createFormValidation<T>(\\n model: FormModel<T>,\\n schema: ValidationSchema<T>,\\n options?: ValidationStrategyOptions,\\n): FormValidationController;\\n```\\n\\n- `useFormValidation` мемоизирует контроллер по `[model, schema, strategy, debounce, liveAfterSubmit]`,\\n армит стратегию в `useEffect` (SSR-safe), а `submit()` = `controller.validate()`.\\n- `createFormValidation` ЧИСТА до `start()` (никаких подписок) → SSR-safe; `start()` возвращает\\n `dispose` и арминует триггеры только на клиенте.","patterns":[],"antiPatterns":[{"why":"schema пересоздаётся каждый рендер → контроллер и дедуп раннера ломаются","bad":"function MyForm() {\\n const schema = defineValidationSchema<Form>(({ model }) => { … }); // новая ссылка на каждый рендер\\n useFormValidation({ model, schema, strategy: \'change\' });\\n}","correctNote":"Стабильная ссылка: module-level const (или useMemo с пустыми deps)","correct":"const formValidation = defineValidationSchema<Form>(({ model }) => { … });\\nfunction MyForm() {\\n useFormValidation({ model, schema: formValidation, strategy: \'change\' });\\n}"},{"why":"Node-level updateOn (Слой B) И активная schema-стратегия на ОДНОМ поле → оба пишут ошибки в ноду → мерцание","bad":"// узел поля: { updateOn: \'blur\', … } + useFormValidation({ strategy: \'blur\', schema: включает это же поле })","correctNote":"Одно поле обслуживает ОДИН слой: либо node-level updateOn, либо schema-стратегия — не оба сразу"},{"why":"start() на сервере — арминует реактивные подписки при SSR","bad":"const ctrl = createFormValidation(model, schema, { strategy: \'change\' });\\nctrl.start(); // на сервере подписок быть не должно","correctNote":"Фабрика чиста до start(); армить только на клиенте (useFormValidation делает это в useEffect)","correct":"const ctrl = createFormValidation(model, schema, { strategy: \'change\' });\\nif (typeof window !== \'undefined\') ctrl.start();"}],"examples":[],"troubleshooting":[],"seeAlso":["[28-submit-and-reset.md](./28-submit-and-reset.md) — submit-флоу и `validateModel` (движок под стратегией)","[27-revalidate-when.md](./27-revalidate-when.md) — ручные триггеры перевалидации (низкоуровневый примитив)","[31-async-validator-debounce.md](./31-async-validator-debounce.md) — async-правила и отмена устаревших прогонов","[13-multi-step.md](./13-multi-step.md) — per-step / полная валидация wizard (`validateStep` / `validateAll`)"],"sections":[{"heading":"Purpose","slug":"purpose-9"},{"heading":"API","slug":"api-8"},{"heading":"Examples","slug":"examples-8"},{"heading":"Anti-patterns","slug":"anti-patterns-8"},{"heading":"See also","slug":"see-also-10"}],"terms":[["model",22],["submit",22],["const",16],["schema",14],["strategy",14],["change",12],["form",11],["useformvalidation",10],["reformer",10],["debounce",10],["core",9],["только",9],["blur",9],["validate",9],["createformvalidation",8],["start",8],["afterfirstsubmit",7],["ctrl",7],["level",6],["function",6],["live",6],["boolean",6],["email",6],["шага",6],["validation",5],["стратегия",5],["definevalidationschema",5],["react",5],["ssr",5],["typescript",5],["dispose",5],["import",5],["from",5],["при",5],["слой",4],["ошибок",4],["updateon",4],["поля",4],["под",4],["usememo",4],["default",4],["liveaftersubmit",4],["isvalidating",4],["true",4],["ошибки",4],["клиенте",4],["required",4],["username",4],["password",4],["async",4],["step",4],["config",4],["validatemodel",3],["дедуп",3],["node",3],["триггеры",3],["api",3],["headless",3],["ссылка",3],["module",3],["validationstrategykind",3],["promise",3],["type",3],["раскрыть",3],["все",3],["армит",3],["useeffect",3],["арминует",3],["touched",3],["false",3],["каждый",3],["тихо",3],["minlength",3],["registrationdata",3],["string",3],["registrationvalidation",3],["onsubmit",3],["await",3],["formfield",3],["control",3],["wizard",3],["definesteps",3],["usewizardstepvalidation",3],["validateall",3],["formwizard",3],["confirm",3],["поле",3],["стратегии",2],["валидации",2],["когда",2],["ручной",2],["markastouched",2],["движок",2],["отмена",2],["устаревших",2],["прогонов",2],["раскрытие",2],["правила",2],["фабрика",2],["для",2],["formmodel",2],["validationschema",2],["стабильная",2],["number",2],["interface",2],["validationstrategyoptions",2],["formvalidationcontroller",2],["прогон",2],["touch",2],["переводит",2],["фазу",2],["void",2],["реактивные",2],["подписки",2],["readonly",2],["контроллер",2],["стратегию",2],["safe",2],["чиста",2],["подписок",2],["всё",2],["фокуса",2],["ввод",2],["один",2],["дальше",2],["далее",2],["живую",2],["tsx",2],["createmodel",2],["createform",2],["раннера",2],["нет",2],["return",2],["button",2],["внутри",2],["шаг",2],["снимает",2],["per",2],["validatestep",2],["правил",2],["loan",2],["applicant",2],["валидация",2],["loanstepbody",2],["рендер",2],["myform",2],["formvalidation",2],["оба",2],["это",2],["либо",2],["сервере",2],["and",2],["reset",2],["revalidate",2],["when",2],["validator",2],["multi",2]]}],"symbols":[{"name":"aggregateInto","kind":"function","signature":"export function aggregateInto<TItem>(\\n array: object,\\n derive: (rows: TItem[]) => Array<{ index: number; patch: Partial<TItem> }>\\n): void","summary":"Агрегатная запись в строки массива.","description":"Агрегатная запись в строки массива. `derive(snapshot)` получает СНИМОК строк и возвращает список\\n`{ index, patch }`, который применяется к строкам. Записи КОАЛЕСИРУЮТСЯ в один отложенный проход на\\nфинальном состоянии — поэтому массовые синхронные мутации (push в цикле) не вызывают каскад на\\nпромежуточных состояниях. `derive` должна сходиться (на фикспоинте возвращать те же значения).","params":[],"example":"// последняя строка = 100 − Σ(остальные)\\naggregateInto(model.$.rows, (rows) => {\\n const n = rows.length; if (n === 0) return [];\\n const others = rows.slice(0, n - 1).reduce((s, r) => s + r.percent, 0);\\n return [{ index: n - 1, patch: { percent: 100 - others } }];\\n});","examplesCount":1,"topics":["api-reference","api-signatures","complete-import","array-operations"],"sourcePath":"src/form/behaviors/collections.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"AnyFunction","kind":"type","signature":"export type AnyFunction = (...args: never[]) => unknown;","summary":"Тип для проверки на функцию в conditional types Используется вместо Function для type narrowing","description":"Тип для проверки на функцию в conditional types\\nИспользуется вместо Function для type narrowing","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"apply","kind":"function","signature":"export function apply<T>(...schemas: ValidationSchema<T>[]): void","summary":"Композиция под-схем в текущую (над той же моделью scope).","description":"Композиция под-схем в текущую (над той же моделью scope). Заменяет пошаговую группировку.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","multi-step","extended-mistakes","nonexistent-api","sync-fields","submit-and-reset"],"sourcePath":"src/form/validation/operators.ts","entries":["./behaviors","./validation"],"package":"@reformer/core","usage":4},{"name":"applyEach","kind":"function","signature":"export function applyEach<TItem>(array: object, itemSchema: FormBehavior<TItem>): void","summary":"Применить под-схему к КАЖДОМУ элементу динамического массива (per-item поведение).","description":"Применить под-схему к КАЖДОМУ элементу динамического массива (per-item поведение).\\nРеагирует на добавление/удаление строк: новым строкам поведение применяется, удалённым — отписывается.\\n\\nПод-схема получает scope строки: `model` (под-модель строки — `row.$.field`) и `form` (нода строки).\\n- Value-операции (`compute`/`copyFrom`/`transformValue` на `row.$.*`) работают всегда.\\n- Node-операции (`enableWhen`/`updateComponentProps`/`reset` через `form.*`) требуют, чтобы массив был\\n МАТЕРИАЛИЗОВАН в форме (узел `{ array, item }` в схеме) — тогда `form` строки = та же нода, что\\n рендерится, а её сигналы зарегистрированы (`enableWhen` резолвит ноду). Без материализации доступ\\n к `form.*` бросит понятную ошибку (см. {@link unmaterializedRowForm}).","params":[],"example":"applyEach(model.$.items, defineFormBehavior<Item>(({ model: row, form }) => {\\n compute(row.$.lineTotal, () => row.qty * row.price); // value-op — всегда\\n enableWhen(row.$.discount, () => row.qty > 10); // node-op — нужна материализация массива\\n}));","examplesCount":1,"topics":["api-reference","api-signatures","troubleshooting","complete-import","extended-mistakes","array-operations"],"sourcePath":"src/form/behaviors/collections.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"ArrayControlState","kind":"interface","signature":"export interface ArrayControlState<T> {\\n /**\\n * Массив текущих значений всех элементов.\\n *\\n * @example\\n * ```tsx\\n * const { value } = useFormControl(phonesArray);\\n * console.log(value);\\n * // [{ type: \'mobile\', number: \'+1234567890\' }, { type: \'home\', number: \'+0987654321\' }]\\n * ```\\n */\\n value: T[];\\n\\n /**\\n * Количество элементов в массиве.\\n * Эквивалентно value.length, но оптимизировано для реактивности.\\n *\\n * @example\\n * ```tsx\\n * const { length } = useFormControl(itemsArray);\\n *\\n * return (\\n * <div>\\n * <span>Items: {length}</span>\\n * {length >= 10 && <span>Maximum reached</span>}\\n * </div>\\n * );\\n * ```\\n */\\n length: number;\\n\\n /**\\n * Флаг асинхронной валидации.\\n * `true` когда выполняется асинхронный валидатор массива или любого элемента.\\n */\\n pending: boolean;\\n\\n /**\\n * Массив ошибок валидации уровня массива.\\n * Не включает ошибки отдельных элементов.\\n *\\n * @example\\n * ```tsx\\n * // Валидатор массива\\n * validators.apply(phonesArray, {\\n * validator: (phones) => phones.length >= 1,\\n * message: \'At least one phone required\'\\n * });\\n *\\n * // В компоненте\\n * const { errors } = useFormControl(phonesArray);\\n * // errors содержит ошибку \\"At least one phone required\\" если массив пуст\\n * ```\\n */\\n errors: ValidationError[];\\n\\n /**\\n * Флаг валидности массива и всех его элементов.\\n * `true` только когда массив и все вложенные элементы валидны.\\n */\\n valid: boolean;\\n\\n /**\\n * Флаг невалидности.\\n * `true` когда есть ошибки в массиве или любом элементе.\\n */\\n invalid: boolean;\\n\\n /**\\n * Флаг взаимодействия.\\n * `true` после взаимодействия с любым элементом массива.\\n */\\n touched: boolean;\\n\\n /**\\n * Флаг изменения.\\n * `true` когда значение массива отличается от начального.\\n *\\n * @example\\n * ```tsx\\n * const { dirty } = useFormControl(itemsArray);\\n *\\n * return (\\n * <div>\\n * {dirty && <span>* Unsaved changes</span>}\\n * <button disabled={!dirty}>Save</button>\\n * </div>\\n * );\\n * ```\\n */\\n dirty: boolean;\\n\\n /**\\n * Флаг отключения массива.\\n * `true` когда массив отключён (`ArrayNode.disable()`), в том числе через\\n * распространение disable от родительской группы.\\n *\\n * Используйте для отключения UI-действий добавления/удаления, когда массив\\n * структурно неизменяем.\\n *\\n * @example\\n * ```tsx\\n * const { disabled } = useFormControl(itemsArray);\\n *\\n * return <button disabled={disabled} onClick={() => control.push()}>Add</button>;\\n * ```\\n */\\n disabled: boolean;\\n}","summary":"Состояние массива формы, возвращаемое хуком {@link useFormControl} для {@link ArrayNode}.","description":"Состояние массива формы, возвращаемое хуком {@link useFormControl} для {@link ArrayNode}.\\n\\nСодержит реактивные данные массива: значения элементов, длину, состояние валидации\\nи флаги взаимодействия.","params":[],"example":"Список с динамическим добавлением\\n```tsx\\ninterface Phone {\\ntype: string;\\nnumber: string;\\n}\\n\\ninterface Props {\\ncontrol: ArrayNode<Phone>;\\n}\\n\\nfunction PhoneList({ control }: Props) {\\nconst { length, valid } = useFormControl(control);\\n\\nreturn (\\n<div>\\n{control.map((item, index) => (\\n<PhoneItem\\n key={item.id}\\n control={item}\\n onRemove={() => control.removeAt(index)}\\n/>\\n))}\\n\\n{length === 0 && <p>No phones added</p>}\\n\\n<button onClick={() => control.push({ type: \'mobile\', number: \'\' })}>\\nAdd Phone\\n</button>\\n\\n{!valid && <p className=\\"error\\">Please fix phone errors</p>}\\n</div>\\n);\\n}\\n```","examplesCount":1,"related":["useFormControl","FieldControlState"],"sourcePath":"src/platforms/react/hooks/types.ts","entries":["."],"package":"@reformer/core"},{"name":"ArrayNode","kind":"class","signature":"export class ArrayNode<T extends object> extends FormNode<T[]> {\\n // ============================================================================\\n // Приватные поля\\n // ============================================================================ /* … */ }","summary":"ArrayNode - массив форм с реактивным состоянием","description":"ArrayNode - массив форм с реактивным состоянием","params":[],"example":"```typescript\\nconst array = new ArrayNode({\\n title: { value: \'\', component: InputField },\\n price: { value: 0, component: InputField },\\n});\\n\\narray.push({ title: \'Item 1\', price: 100 });\\narray.at(0)?.title.setValue(\'Updated\');\\nconsole.log(array.length.value); // 1\\n```","examplesCount":1,"topics":["api-reference","common-mistakes","complete-import","arrays","type-safety-recipes"],"sourcePath":"src/form/nodes/array-node.ts","entries":["."],"package":"@reformer/core","usage":8},{"name":"ArrayNodeLike","kind":"interface","signature":"export interface ArrayNodeLike {\\n at(index: number): FormNode<unknown> | undefined;\\n length: unknown;\\n}","summary":"Интерфейс для узлов, похожих на ArrayNode (с методом at) Используется для duck typing при обходе путей","description":"Интерфейс для узлов, похожих на ArrayNode (с методом at)\\nИспользуется для duck typing при обходе путей","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"AsyncRule","kind":"type","signature":"export type AsyncRule<TField> = (\\n value: TField,\\n ctx: { signal: AbortSignal }\\n) => Promise<ValidationError | null>;","summary":"Асинхронное правило поля.","description":"Асинхронное правило поля. Получает `AbortSignal` для отмены устаревших ответов (быстрый повторный\\nпрогон той же схемы отменяет предыдущий). Сетевой сбой не должен блокировать — ловите и возвращайте `null`.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-mistakes","complete-import","nonexistent-api","async-validator-debounce"],"sourcePath":"src/form/validation/types.ts","entries":["./validation"],"package":"@reformer/core","usage":9},{"name":"AsyncValidatorFn","kind":"type","signature":"export type AsyncValidatorFn<T = FormValue> = (\\n value: T,\\n options?: AsyncValidatorOptions\\n) => Promise<ValidationError | null>;","summary":"Асинхронная функция валидации","description":"Асинхронная функция валидации","params":[["value","- Значение для валидации"],["options","- Опции валидации (опционально)"]],"returns":"Promise с ошибкой валидации или null если значение валидно","example":"```typescript\\n// Простой валидатор (без поддержки отмены)\\nconst emailExists: AsyncValidatorFn<string> = async (value) => {\\n const exists = await checkEmail(value);\\n return exists ? { code: \'exists\', message: \'Email already exists\' } : null;\\n};\\n\\n// Валидатор с поддержкой отмены\\nconst emailExistsAbortable: AsyncValidatorFn<string> = async (value, options) => {\\n const exists = await fetch(`/api/check-email?email=${value}`, {\\n signal: options?.signal // Передаём signal в fetch для отмены запроса\\n });\\n return exists ? { code: \'exists\', message: \'Email already exists\' } : null;\\n};\\n```","examplesCount":1,"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"AsyncValidatorOptions","kind":"interface","signature":"export interface AsyncValidatorOptions {\\n /**\\n * AbortSignal для отмены валидации\\n * Позволяет отменить асинхронную операцию при новой валидации\\n */\\n signal?: AbortSignal;\\n}","summary":"Опции для асинхронного валидатора","description":"Опции для асинхронного валидатора","params":[],"examplesCount":0,"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"BehaviorCleanup","kind":"type","signature":"export type BehaviorCleanup = () => void;","summary":"Функция отписки от behavior-эффекта.","description":"Функция отписки от behavior-эффекта.","params":[],"examplesCount":0,"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"BehaviorScope","kind":"type","signature":"export type BehaviorScope<T> = { model: FormModel<T>; form: FormProxy<T> };","summary":"Контекст схемы поведения: модель (значения/сигналы) + форма (ноды).","description":"Контекст схемы поведения: модель (значения/сигналы) + форма (ноды).","params":[],"examplesCount":0,"sourcePath":"src/form/behaviors/types.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"buildValidation","kind":"function","signature":"export function buildValidation<T>(\\n model: FormModel<T>,\\n validation?: FormValidation<T> | ValidationSchema<T>\\n): FormValidationBundle<T> | undefined","summary":"Собрать {@link FormValidationBundle} из правил.","description":"Собрать {@link FormValidationBundle} из правил. Принимает либо готовую схему (сахар для простых\\nформ), либо {@link FormValidation} с шагами и стратегией.\\n\\nСхема для `validateAll` собирается ОДИН раз на бандл — иначе ломается дедупликация прогонов.","params":[["model","- Модель, по которой идут прогоны."],["validation","- Правила; `undefined` — валидации у формы нет."]],"returns":"Бандл валидации либо `undefined`, если правила не заданы.","example":"```ts\\nconst v = buildValidation(model, {\\n steps: { loan: loanRules, applicant: applicantRules, confirm: null },\\n extras: crossFieldRules,\\n strategy: \'blur\',\\n});\\nawait v!.validateStep(1); // правила шага `loan`\\nawait v!.validateAll(); // все шаги + extras\\n```","examplesCount":1,"sourcePath":"src/form/validation/config.ts","entries":["."],"package":"@reformer/core"},{"name":"ChangeContext","kind":"interface","signature":"export interface ChangeContext {\\n signal: AbortSignal;\\n}","summary":"Контекст async-реакции: `signal` аннулируется, когда поле меняется снова до завершения колбэка.","description":"Контекст async-реакции: `signal` аннулируется, когда поле меняется снова до завершения колбэка.","params":[],"examplesCount":0,"sourcePath":"src/form/behaviors/types.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"compute","kind":"function","signature":"export function compute<R>(\\n target: Signal<R>,\\n read: () => R,\\n options?: { when?: () => boolean }\\n): void","summary":"Вычисляемое поле с auto-tracking: `target = read()` при изменении прочитанных сигналов.","description":"Вычисляемое поле с auto-tracking: `target = read()` при изменении прочитанных сигналов.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","extended-mistakes","project-structure","nonexistent-api","conditional-fields","reading-values","compute-vs-watch","array-operations","cycle-detection","copy-from","sync-fields","reset-when","transform-value","revalidate-when","type-safety-recipes"],"sourcePath":"src/form/behaviors/operators.ts","entries":["./behaviors"],"package":"@reformer/core","usage":24},{"name":"computeFrom","kind":"function","signature":"export function computeFrom<R>(\\n sources: ReadonlySignal<any>[],\\n target: Signal<R>,\\n fn: (...values: any[]) => R,\\n options?: { when?: (...values: any[]) => boolean }\\n): BehaviorCleanup","summary":"Вычисляемое поле: `target = fn(...sourceValues)` при изменении источников.","description":"Вычисляемое поле: `target = fn(...sourceValues)` при изменении источников.","params":[["sources","Сигналы-источники (`model.$.a`, `model.$.b`)."],["target","Сигнал-цель (`model.$.total`)."],["fn","Функция вычисления значения."]],"returns":"Cleanup для отписки.","example":"```typescript\\ncomputeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price * qty);\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","extended-mistakes","reading-values","compute-vs-watch","cycle-detection","type-safety-recipes"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":6},{"name":"ConfigWithSchema","kind":"interface","signature":"export interface ConfigWithSchema {\\n schema: unknown;\\n initialItems?: unknown[];\\n}","summary":"Конфиг с полем schema (для ArrayConfig)","description":"Конфиг с полем schema (для ArrayConfig)","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"ConfigWithValue","kind":"interface","signature":"export interface ConfigWithValue {\\n value: unknown;\\n}","summary":"Конфиг с полем value (для извлечения значений)","description":"Конфиг с полем value (для извлечения значений)","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"copyFrom","kind":"function","signature":"export function copyFrom<T>(\\n source: ReadonlySignal<T>,\\n target: Signal<T>,\\n options?: { when?: () => boolean; transform?: (value: T) => T }\\n): BehaviorCleanup","summary":"Копирование значения `source → target` (опционально по условию/с трансформом).","description":"Копирование значения `source → target` (опционально по условию/с трансформом).","params":[],"example":"```typescript\\ncopyFrom(model.$.email, model.$.emailAdditional, { when: () => model.sameEmail });\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","complete-import","project-structure","conditional-fields","reading-values","cycle-detection","copy-from","sync-fields","transform-value"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":10},{"name":"CORE_RUNTIME_TOKEN","kind":"const","signature":"export const CORE_RUNTIME_TOKEN: object","summary":"Штамп копии рантайма ядра.","description":"Штамп копии рантайма ядра.\\n\\nЕдинственное назначение — быть объектом, уникальным в пределах ОДНОЙ копии модуля. Две\\nнезависимо загруженные копии `@reformer/core` дадут два разных объекта, и по их несовпадению\\nguard распознаёт дубль рантайма.\\n\\nПочему именно объект, а не строка с версией: две копии ОДНОЙ версии ломают всё ровно так же,\\nкак две копии разных версий, — раздваиваются модульные `WeakMap` (`derived-registry`,\\n`signal-node-registry`) и перестают работать проверки `instanceof Signal`. Сравнение версий\\nтакой случай пропустило бы.","params":[],"example":"```ts\\nimport { CORE_RUNTIME_TOKEN } from \'@reformer/core\';\\nimport { stampRuntime } from \'@reformer/form-registry/guard\';\\n\\nstampRuntime(\'@reformer/core\', CORE_RUNTIME_TOKEN);\\n```","examplesCount":1,"sourcePath":"src/runtime-token.ts","entries":["."],"package":"@reformer/core"},{"name":"CoreForm","kind":"interface","signature":"export interface CoreForm<T> {\\n model: FormModel<T>;\\n form: FormProxy<T>;\\n validation?: FormValidationBundle<T>;\\n}","summary":"Результат {@link createCoreForm}: модель, форма и (если заданы правила) собранная валидация.","description":"Результат {@link createCoreForm}: модель, форма и (если заданы правила) собранная валидация.","params":[],"examplesCount":0,"sourcePath":"src/form/create-core-form.ts","entries":["."],"package":"@reformer/core","usage":2},{"name":"createCoreForm","kind":"function","signature":"export function createCoreForm<T extends object>(config: CreateCoreFormConfig<T>): CoreForm<T>","summary":"Собрать модель, форму и валидацию за один проход.","description":"Собрать модель, форму и валидацию за один проход.","params":[["config","- {@link CreateCoreFormConfig}: (`initial` | `model`) + опц. `schema`, `behavior`,\\n`validation`, `seed`, `setup`."]],"returns":"","example":"```tsx\\nconst credit = useFormBundle(() =>\\n createCoreForm<CreditForm>({\\n model: createCreditModel(),\\n schema: buildCreditSchema,\\n behavior: creditBehavior,\\n validation: { steps: { loan: loanRules, confirm: null }, extras: crossRules },\\n })\\n);\\nreturn <FormWizard form={credit.form} config={credit.validation} steps={STEPS} />;\\n```","examplesCount":1,"topics":["quick-start","project-structure"],"sourcePath":"src/form/create-core-form.ts","entries":["."],"package":"@reformer/core","usage":16},{"name":"CreateCoreFormConfig","kind":"interface","signature":"export interface CreateCoreFormConfig<T> extends CreateFormConfigBase<T, CoreForm<T>> {\\n /**\\n * Билдер схемы формы. Именно функция, а не готовое дерево: листья схемы держат сами сигналы\\n * модели (`value: model.$.email`), поэтому построить дерево до модели нечем.\\n */\\n schema?: (model: FormModel<T>) => FormSchemaNode;\\n}","summary":"Конфиг {@link createCoreForm}.","description":"Конфиг {@link createCoreForm}.","params":[],"examplesCount":0,"sourcePath":"src/form/create-core-form.ts","entries":["."],"package":"@reformer/core"},{"name":"createForm","kind":"function","signature":"export function createForm<T>(args: CreateFormFromModelArgs<T>): FormProxy<T>;","summary":"Создать форму из {@link FormModel} + единой схемы (архитектура M1, рекомендуемый путь).","description":"Создать форму из {@link FormModel} + единой схемы (архитектура M1, рекомендуемый путь).","params":[["args","- Модель данных, layout-схема (component/componentProps) и (опционально) поведение"]],"returns":"Типизированная форма с Proxy-доступом к полям","example":"Архитектура M1: `createModel` + layout-схема + `createForm({ model, schema })`\\n```typescript\\nimport { createModel, createForm } from \'@reformer/core\';\\nimport { defineValidationSchema, validate, validateModel } from \'@reformer/core/validation\';\\nimport { required, email, minLength } from \'@reformer/core/validators\';\\n\\ninterface UserForm {\\nemail: string;\\npassword: string;\\n}\\n\\nconst model = createModel<UserForm>({ email: \'\', password: \'\' });\\n\\n// Layout-схема НЕ несёт validators — только component/componentProps.\\nconst schema = {\\nchildren: [\\n{ value: model.$.email, component: InputField },\\n{ value: model.$.password, component: InputField },\\n],\\n};\\n\\nconst form = createForm<UserForm>({ model, schema });\\nform.email.setValue(\'test@mail.com\');\\n\\n// Валидация — ОТДЕЛЬНАЯ схема, прогон внешним раннером (ошибки сами доезжают до нод):\\nconst validation = defineValidationSchema<UserForm>(({ model }) => {\\nvalidate(model.$.email, [required(), email()]);\\nvalidate(model.$.password, [required(), minLength(8)]);\\n});\\nconst ok = await validateModel(model, validation);\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","troubleshooting","complete-import","formschema","arrays","ui-components","nonexistent-api","conditional-fields","compute-vs-watch","copy-from","reset-when","transform-value","submit-and-reset","async-preload","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/create-form.ts","entries":["."],"package":"@reformer/core","usage":11},{"name":"CreateFormConfigBase","kind":"interface","signature":"export interface CreateFormConfigBase<T, B> {\\n /** Начальные значения — из них создаётся модель. Взаимоисключимо с `model`. */\\n initial?: T;\\n /** Готовая модель (если создана отдельной фабрикой). Приоритетнее `initial`. */\\n model?: FormModel<T>;\\n /** Декларативное поведение модели (compute/copyFrom/enableWhen/onChange). */\\n behavior?: FormBehavior<T>;\\n /** Правила валидации: готовая схема либо {@link FormValidation} со стратегией и шагами. */\\n validation?: FormValidation<T> | ValidationSchema<T>;\\n /**\\n * Правка модели ДО сборки формы. Нужна там, где значение обязано существовать к моменту\\n * построения нод — например, массив, наполняемый из вычислений (реактивные `onChange` на\\n * инициализации не срабатывают).\\n */\\n seed?: (model: FormModel<T>) => void;\\n /**\\n * Донастройка ПОСЛЕ сборки. Единственное место для правок, которые обязаны идти следом за\\n * `createForm`: поле, чьё значение уже массив, ноды не получает (см. `buildModelConfig`),\\n * поэтому такой префилл выполняется здесь.\\n */\\n setup?: (bundle: B) => void;\\n}","summary":"Общая часть конфига всех фабрик формы.","description":"Общая часть конфига всех фабрик формы.","params":[],"examplesCount":0,"sourcePath":"src/form/create-core-form.ts","entries":["."],"package":"@reformer/core"},{"name":"createFormFromModel","kind":"function","signature":"export function createFormFromModel<T>(args: CreateFormFromModelArgs<T>): FormProxy<T>","summary":"Собрать форму из {@link FormModel} и единой схемы (низкоуровневая фабрика архитектуры M1).","description":"Собрать форму из {@link FormModel} и единой схемы (низкоуровневая фабрика архитектуры M1).\\n\\nЗначения принадлежат модели (источник истины), ноды формы держат UI/валидационное состояние и\\nссылаются на сигналы модели по идентичности (`node.value === model.$.path`). Обходит структуру\\nмодели, привязывает конфиг поля (component/componentProps) из схемы, материализует\\ntop-level массивы как {@link ModelArrayNode}, заполняет реестр сигнал→нода (для `enableWhen`/\\nроутинга ошибок) и, при наличии, запускает декларативное поведение (cleanup живёт на форме).\\n\\nОбычно вызывается неявно через {@link createForm} с аргументом `{ model, schema }` — прямой вызов\\nнужен редко (например, для построения формы элемента массива).","params":[["args","- Модель, единая схема и (опционально) декларативное поведение {@link CreateFormFromModelArgs}"]],"returns":"Типизированная форма с Proxy-доступом к полям {@link FormProxy}","example":"Форма из модели + схемы (эквивалент `createForm({ model, schema })`)\\n```typescript\\nimport { createModel, createFormFromModel } from \'@reformer/core\';\\n\\ninterface Form {\\nemail: string;\\nprofile: { name: string; age: number };\\n}\\n\\nconst model = createModel<Form>({ email: \'\', profile: { name: \'\', age: 0 } });\\nconst schema = {\\ncomponent: Section,\\nchildren: [\\n// Layout несёт только component/componentProps; правила — в отдельной ValidationSchema.\\n{ value: model.$.email, component: InputField },\\n// вложенная группа: `model.$.profile.name` (≡ под-модель `model.profile.$.name` — тот же сигнал)\\n{ value: model.$.profile.name, component: InputField },\\n],\\n};\\n\\nconst form = createFormFromModel<Form>({ model, schema });\\n\\n// Двусторонняя связь нода ↔ модель:\\nform.email.setValue(\'user@mail.com\');\\nconsole.log(model.email); // \'user@mail.com\'\\n```","examplesCount":1,"related":["createForm"],"sourcePath":"src/form/create-form.ts","entries":["."],"package":"@reformer/core"},{"name":"CreateFormFromModelArgs","kind":"interface","signature":"export interface CreateFormFromModelArgs<T> {\\n /** Реактивная модель данных (источник истины значений). */\\n model: FormModel<T>;\\n /**\\n * Единая Schema (дерево узлов {@link FormSchemaNode}). createForm обходит её и привязывает конфиг\\n * поля к ноде по идентичности сигнала (`node.value === model.$.path`). Опциональна.\\n */\\n schema?: FormSchemaNode;\\n /**\\n * Декларативная схема поведения ({@link defineFormBehavior}). Запускается ПОСЛЕ построения нод и\\n * заполнения реестра сигнал→нода; cleanup живёт на форме и вызывается в `form.dispose()`.\\n */\\n behavior?: FormBehavior<T>;\\n}","summary":"Аргументы createForm под архитектуру M1: данные приходят из {@link FormModel}, конфиг полей (component/componentProps) — из единой схемы.","description":"Аргументы createForm под архитектуру M1: данные приходят из {@link FormModel},\\nконфиг полей (component/componentProps) — из единой схемы.","params":[],"examplesCount":0,"sourcePath":"src/form/create-form.ts","entries":["."],"package":"@reformer/core"},{"name":"createFormValidation","kind":"function","signature":"export function createFormValidation<T>(\\n model: FormModel<T>,\\n schema: ValidationSchema<T>,\\n options: ValidationStrategyOptions = {}\\n): FormValidationController","summary":"Собрать контроллер валидации формы с выбранной стратегией запуска.","description":"Собрать контроллер валидации формы с выбранной стратегией запуска. Переиспользует\\n{@link validateModel} как единственный движок прогона.\\n\\nФабрика ЧИСТАЯ до `start()` (никаких подписок) — безопасна для SSR/headless. Реактивные триггеры\\nарминуются только в `start()` (в React — из `useEffect`).","params":[["model","- Модель данных."],["schema","- Схема валидации. **Стабильная ссылка** (иначе `validateModel` не отменит устаревший прогон)."],["options","- {@link ValidationStrategyOptions}."]],"example":"```ts\\nconst ctrl = createFormValidation(model, schema, { strategy: \'afterFirstSubmit\', debounce: 300 });\\nconst dispose = ctrl.start(); // на клиенте\\nconst ok = await ctrl.validate(); // submit → раскрыть все ошибки\\ndispose();\\n```","examplesCount":1,"topics":["validation-strategy"],"sourcePath":"src/form/validation/strategy.ts","entries":["./validation"],"package":"@reformer/core"},{"name":"createModel","kind":"function","signature":"export function createModel<T extends object>(initial: T): FormModel<T>","summary":"Создать реактивную модель данных формы (слой M1).","description":"Создать реактивную модель данных формы (слой M1).","params":[["initial","Начальные значения (объект). Определяют форму данных и initial-снимок."]],"returns":"","example":"```typescript\\nconst model = createModel<{ email: string; profile: { name: string }; tags: string[] }>({\\n email: \'\',\\n profile: { name: \'\' },\\n tags: [],\\n});\\nmodel.email = \'a@b.c\';\\nmodel.$.email.value; // \'a@b.c\' (сигнал)\\n// вложенная объект-группа — под-модель FormModel (value-доступ + `.$` + API):\\nmodel.profile.name = \'Ada\'; // value-запись\\nmodel.$.profile.name.value; // \'Ada\' (сигнал; ≡ model.profile.$.name у под-модели)\\nmodel.profile.get(); // { name: \'Ada\' }\\nmodel.tags.push(\'x\');\\nmodel.get(); // { email: \'a@b.c\', profile: { name: \'Ada\' }, tags: [\'x\'] }\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-mistakes","complete-import","form-types","formschema","arrays","project-structure","ui-components","nonexistent-api","conditional-fields","submit-and-reset","async-preload","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/model/create-model.ts","entries":[".","./model"],"package":"@reformer/core","usage":9},{"name":"cross","kind":"function","signature":"export function cross<TSnapshot>(\\n sig: PathAwareSignal<unknown>,\\n fn: (form: TSnapshot) => ValidationError | null\\n): void","summary":"Cross-field правило: `fn` получает СНАПШОТ модели текущего scope (`model.get()`) и вешает ошибку на `sig`.","description":"Cross-field правило: `fn` получает СНАПШОТ модели текущего scope (`model.get()`) и вешает ошибку на `sig`.\\nДля элементов массива / под-моделей захватывайте нужный снапшот в замыкание (`const item = im.get()`),\\nт.к. `fn` всегда получает модель ТЕКУЩЕГО scope (корень прогона), а не под-модель.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","arrays","extended-mistakes","project-structure","nonexistent-api","conditional-fields","compute-vs-watch","array-operations","revalidate-when","submit-and-reset","type-safety-recipes","async-validator-debounce"],"sourcePath":"src/form/validation/operators.ts","entries":["./validation"],"package":"@reformer/core","usage":34},{"name":"defer","kind":"function","signature":"export function defer(fn: () => void): void","summary":"Отложенная запись вне effect-контекста (микротаск) — защита от «Cycle detected».","description":"Отложенная запись вне effect-контекста (микротаск) — защита от «Cycle detected».","params":[],"examplesCount":0,"topics":["api-reference"],"sourcePath":"src/form/behaviors/context.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"defineFormBehavior","kind":"function","signature":"export function defineFormBehavior<T>(setup: (scope: BehaviorScope<T>) => void): FormBehavior<T>","summary":"Описать поведение формы декларативно.","description":"Описать поведение формы декларативно. Возвращает {@link FormBehavior} для `createForm({ behavior })`.","params":[],"example":"```ts\\nexport const myBehavior = defineFormBehavior<MyForm>(({ model, form }) => {\\n compute(model.$.total, () => model.price * model.qty);\\n enableWhen([model.$.city], () => Boolean(model.country));\\n onChange(model.$.country, async (c) => form.city.updateComponentProps({ options: await load(c) }));\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","formschema","async-watchfield","array-cleanup","extended-mistakes","project-structure","nonexistent-api","conditional-fields","reading-values","compute-vs-watch","array-operations","copy-from","sync-fields","reset-when","transform-value","revalidate-when","async-preload","type-safety-recipes","async-validator-debounce","async-options-loading"],"sourcePath":"src/form/behaviors/context.ts","entries":["./behaviors"],"package":"@reformer/core","usage":8},{"name":"defineValidationSchema","kind":"function","signature":"export function defineValidationSchema<T>(schema: ValidationSchema<T>): ValidationSchema<T>","summary":"Тонкая identity-обёртка для типизации/discoverability (как `defineFormBehavior`).","description":"Тонкая identity-обёртка для типизации/discoverability (как `defineFormBehavior`). Возвращает схему как есть.","params":[],"example":"```ts\\nexport const step1 = defineValidationSchema<LoanForm>(({ model }) => {\\n validate(model.$.loanAmount, [required(), min(50000)]);\\n});\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-patterns","common-mistakes","complete-import","formschema","arrays","multi-step","extended-mistakes","project-structure","nonexistent-api","conditional-fields","array-operations","revalidate-when","submit-and-reset","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/validation/run.ts","entries":["./validation"],"package":"@reformer/core","usage":25},{"name":"disableWhen","kind":"function","signature":"export function disableWhen(\\n target: ReadonlySignal<unknown>,\\n condition: () => boolean,\\n options?: { resetOnDisable?: boolean }\\n): BehaviorCleanup","summary":"Условное выключение поля (инверсия {@link enableWhen}).","description":"Условное выключение поля (инверсия {@link enableWhen}). Резолвит ноду по сигналу-цели через реестр\\nсигнал→нода и вызывает `disable()`, когда `condition` истинно (+`reset()` при `resetOnDisable`).\\n`condition` реактивен (читает свои сигналы модели).","params":[["target","Сигнал-цель поля (`model.$.<path>`)."],["condition","Реактивное условие; при `true` поле выключается."]],"returns":"Cleanup для отписки.","example":"```typescript\\n// Поле скидки недоступно, пока не выбран промо-тариф\\ndisableWhen(model.$.discount, () => model.plan !== \'promo\', { resetOnDisable: true });\\n```","examplesCount":1,"topics":["api-reference","api-signatures","troubleshooting","complete-import"],"sourcePath":"src/form/behaviors/node.ts","entries":[".","./behaviors"],"package":"@reformer/core","usage":4},{"name":"each","kind":"function","signature":"export function each<U extends object>(\\n arr: ModelArray<U>,\\n itemFn: (item: FormModel<U>) => void\\n): void","summary":"Применить под-правила к КАЖДОМУ элементу текущего массива модели.","description":"Применить под-правила к КАЖДОМУ элементу текущего массива модели.\\n`U extends object` — элементы должны быть под-моделями (объектами); для массива примитивов валидируйте лист напрямую.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-mistakes","complete-import","arrays","extended-mistakes","project-structure","nonexistent-api","array-operations","submit-and-reset"],"sourcePath":"src/form/validation/operators.ts","entries":["./validation"],"package":"@reformer/core","usage":5},{"name":"eachLeafSignal","kind":"function","signature":"export function eachLeafSignal<T>(\\n model: FormModel<T>,\\n visit: (signal: PathAwareSignal<unknown>) => void\\n): void","summary":"Обойти ВСЕ листовые сигналы модели (включая элементы массивов), вызвав `visit` на каждом.","description":"Обойти ВСЕ листовые сигналы модели (включая элементы массивов), вызвав `visit` на каждом.\\n\\nВнутри реактивного `effect` служит подпиской «любое поле изменилось»: `visit(sig => void sig.value)`\\nподписывает на значения листьев, а обход массивов через `items.value` — на их состав. Так строятся\\nтриггеры `change`/`blur` стратегий валидации (см. `createFormValidation`), тем же паттерном, что\\n`revalidateWhen`, но без ручного перечисления зависимостей.","params":[],"examplesCount":0,"sourcePath":"src/model/create-model.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"effect","kind":"function","signature":"export function effect(fn: () => void | (() => void)): void","summary":"Реактивный эффект (авто-dispose).","description":"Реактивный эффект (авто-dispose). Колбэк может вернуть собственный cleanup.","params":[],"examplesCount":0,"topics":["api-reference","common-patterns","async-watchfield","array-cleanup","reading-values","compute-vs-watch","cycle-detection","transform-value","revalidate-when"],"sourcePath":"src/form/behaviors/context.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"email","kind":"function","signature":"export function email<TForm = unknown, TField extends string | null | undefined = string>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора формата email.","description":"Фабрика валидатора формата email.\\n\\nПроверяет по упрощённому regex `^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$`. Пустые значения\\n(`\'\'`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для строкового поля","example":"Проверка формата email\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, email } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.email, [required(), email({ message: \'Введите корректный email\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-patterns","common-mistakes","complete-import","form-types","formschema","ui-components","nonexistent-api","conditional-fields","reading-values","copy-from","transform-value","submit-and-reset","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/validators/email.ts","entries":["./validators"],"package":"@reformer/core","usage":89},{"name":"enableWhen","kind":"function","signature":"export function enableWhen(\\n target: ReadonlySignal<unknown>,\\n condition: () => boolean,\\n options?: { resetOnDisable?: boolean }\\n): BehaviorCleanup","summary":"Условное включение поля (state-операция).","description":"Условное включение поля (state-операция). Резолвит ноду по сигналу-цели через реестр\\nсигнал→нода (заполняется `createForm`) и вызывает `enable()`/`disable()` (+`reset()` при\\n`resetOnDisable`). `condition` реактивен (читает свои сигналы модели).\\n\\nЗапись состояния отложена через `runOutsideEffect` (микротаск) для защиты от «Cycle detected».\\n⚠️ Поле должно быть материализовано в форме (`createForm`) — иначе ноды в реестре нет (например,\\nэлемент массива, который строится per-item).\\n\\n⚠️ Если то же поле одновременно является целью `compute`/`computeFrom`, обязательно ограничь\\ncompute тем же условием (`when`), что и это `enableWhen`. Механизмы не согласованы: `enableWhen`\\nработает со статус-машиной ноды (enable/disable/reset), а `compute` пишет `target.value` напрямую\\nв сигнал модели и проверяет только собственный `options.when` — состояние `disabled` он НЕ смотрит.\\nПоэтому при выключенном поле любое изменение зависимости compute молча заново заполнит его (а с\\n`resetOnDisable` — перезапишет только что сброшенное значение), и так как `getValue()`/`submit`\\nвключают disabled-поля, мусор утечёт в payload. Это аналог правила #13 гайда add-behavior,\\nкоторое сегодня сформулировано только для `copyFrom`; для `compute` то же ограничение обязательно.","params":[],"example":"```typescript\\nenableWhen(model.$.propertyValue, () => model.loanType === \'mortgage\', { resetOnDisable: true });\\n\\n// Поле-цель compute, которое ТАКЖЕ в resetOnDisable enableWhen: compute обязан нести тот же when,\\n// иначе initialPayment заново заполнится в выключенном состоянии и утечёт в submit.\\ncompute(model.$.initialPayment, () => model.propertyValue * 0.2, {\\n when: () => model.loanType === \'mortgage\',\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","formschema","project-structure","nonexistent-api","conditional-fields","reading-values","cycle-detection","reset-when","submit-and-reset","type-safety-recipes"],"sourcePath":"src/form/behaviors/node.ts","entries":[".","./behaviors"],"package":"@reformer/core","usage":18},{"name":"ErrorFilterOptions","kind":"interface","signature":"export interface ErrorFilterOptions {\\n /** Фильтр по коду ошибки */\\n code?: string | string[];\\n\\n /** Фильтр по сообщению (поддерживает частичное совпадение) */\\n message?: string;\\n\\n /** Фильтр по параметрам ошибки */\\n params?: Record<string, FormValue>;\\n\\n /** Кастомный предикат для фильтрации */\\n predicate?: (error: ValidationError) => boolean;\\n}","summary":"Опции для фильтрации ошибок в методе getErrors()","description":"Опции для фильтрации ошибок в методе getErrors()","params":[],"examplesCount":0,"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"ErrorStrategy","kind":"enum","signature":"export enum ErrorStrategy {\\n /**\\n * Пробросить ошибку дальше (throw)\\n * Используется когда ошибка критична и должна остановить выполнение\\n */\\n THROW = \'throw\',\\n\\n /**\\n * Залогировать и проглотить ошибку (продолжить выполнение)\\n * Используется когда ошибка не критична\\n */\\n LOG = \'log\',\\n\\n /**\\n * Конвертировать ошибку в ValidationError\\n * Используется в async validators для отображения ошибки валидации пользователю\\n */\\n CONVERT = \'convert\',\\n}","summary":"Стратегия обработки ошибок Определяет, что делать с ошибкой после логирования","description":"Стратегия обработки ошибок\\n\\nОпределяет, что делать с ошибкой после логирования","params":[],"examplesCount":0,"sourcePath":"src/form/validation/error-handler.ts","entries":["."],"package":"@reformer/core"},{"name":"exclusiveFlag","kind":"function","signature":"export function exclusiveFlag<TItem>(\\n array: object,\\n getFlag: (row: FormModel<TItem>) => Signal<boolean>\\n): void","summary":"Взаимное исключение булева флага среди строк массива (single-selection — «единственный primary»).","description":"Взаимное исключение булева флага среди строк массива (single-selection — «единственный primary»).\\nКогда флаг строки становится true, у остальных строк он сбрасывается в false. Не хрупок к push:\\nновые строки с флагом false исключения не запускают.","params":[],"example":"exclusiveFlag(model.$.contacts, (row) => row.$.primary);","examplesCount":1,"topics":["api-reference","api-signatures","complete-import"],"sourcePath":"src/form/behaviors/collections.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"FieldConfig","kind":"interface","signature":"export interface FieldConfig<T> {\\n /**\\n * Начальное значение-литерал (legacy-путь). Под архитектурой M1 значение приходит из\\n * {@link FieldConfig.valueSignal} (сигнал {@link FormModel}); тогда `value` не требуется.\\n */\\n value?: T | null;\\n /**\\n * Сигнал значения из {@link FormModel} (M1). Если задан — служит источником истины значения\\n * поля (нода не владеет значением, а ссылается на этот сигнал). Имеет приоритет над `value`.\\n */\\n valueSignal?: Signal<T>;\\n /**\\n * UI-компонент поля. Опционален: core-часть можно использовать без ссылки на компонент\\n * (значение/валидация работают без UI; компонент нужен только для рендеринга).\\n */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n component?: ComponentType<any>;\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n componentProps?: any;\\n validators?: ValidatorFn<T>[];\\n asyncValidators?: AsyncValidatorFn<T>[];\\n disabled?: boolean;\\n updateOn?: \'change\' | \'blur\' | \'submit\';\\n /** Задержка (в мс) перед запуском асинхронной валидации */\\n debounce?: number;\\n}","summary":"Конфигурация поля","description":"Конфигурация поля","params":[],"examplesCount":0,"topics":["api-reference","common-mistakes","complete-import","arrays","nonexistent-api","array-operations"],"sourcePath":"src/form/types/deep-schema.ts","entries":["."],"package":"@reformer/core"},{"name":"FieldControlState","kind":"interface","signature":"export interface FieldControlState<T> {\\n /**\\n * Текущее значение поля.\\n *\\n * @example\\n * ```tsx\\n * const { value } = useFormControl(emailField);\\n * console.log(value); // \\"user@example.com\\"\\n * ```\\n */\\n value: T;\\n\\n /**\\n * Флаг асинхронной валидации или загрузки.\\n * `true` когда выполняется асинхронный валидатор.\\n *\\n * @example\\n * ```tsx\\n * const { pending } = useFormControl(usernameField);\\n *\\n * return (\\n * <div>\\n * <input {...props} />\\n * {pending && <Spinner size=\\"small\\" />}\\n * </div>\\n * );\\n * ```\\n */\\n pending: boolean;\\n\\n /**\\n * Флаг отключения поля.\\n * `true` когда поле недоступно для редактирования.\\n *\\n * @example\\n * ```tsx\\n * const { disabled, value } = useFormControl(field);\\n *\\n * return (\\n * <input\\n * value={value}\\n * disabled={disabled}\\n * className={disabled ? \'opacity-50\' : \'\'}\\n * />\\n * );\\n * ```\\n */\\n disabled: boolean;\\n\\n /**\\n * Массив ошибок валидации.\\n * Пустой массив означает отсутствие ошибок.\\n *\\n * @example\\n * ```tsx\\n * const { errors } = useFormControl(field);\\n *\\n * return (\\n * <ul className=\\"error-list\\">\\n * {errors.map((error, i) => (\\n * <li key={i}>{error.message}</li>\\n * ))}\\n * </ul>\\n * );\\n * ```\\n */\\n errors: ValidationError[];\\n\\n /**\\n * Флаг валидности поля.\\n * `true` когда поле прошло все валидации (errors.length === 0).\\n *\\n * @example\\n * ```tsx\\n * const { valid } = useFormControl(field);\\n *\\n * return (\\n * <input className={valid ? \'border-green\' : \'border-gray\'} />\\n * );\\n * ```\\n */\\n valid: boolean;\\n\\n /**\\n * Флаг невалидности поля.\\n * `true` когда есть ошибки валидации (errors.length > 0).\\n * Противоположность {@link valid}.\\n *\\n * @example\\n * ```tsx\\n * const { invalid } = useFormControl(field);\\n *\\n * return (\\n * <input\\n * aria-invalid={invalid}\\n * className={invalid ? \'border-red\' : \'\'}\\n * />\\n * );\\n * ```\\n */\\n invalid: boolean;\\n\\n /**\\n * Флаг взаимодействия с полем.\\n * `true` после того как поле потеряло фокус (blur) хотя бы один раз.\\n *\\n * @example\\n * ```tsx\\n * const { touched, invalid } = useFormControl(field);\\n *\\n * // Показываем ошибку только после взаимодействия\\n * const showError = touched && invalid;\\n * ```\\n */\\n touched: boolean;\\n\\n /**\\n * Флаг для отображения ошибки.\\n * Комбинация touched && invalid - удобный shortcut для UI.\\n *\\n * @example\\n * ```tsx\\n * const { shouldShowError, errors } = useFormControl(field);\\n *\\n * return (\\n * <div>\\n * <input {...props} />\\n * {shouldShowError && (\\n * <span className=\\"error\\">{errors[0]?.message}</span>\\n * )}\\n * </div>\\n * );\\n * ```\\n */\\n shouldShowError: boolean;\\n\\n /**\\n * Пользовательские props для передачи в UI-компоненты.\\n * Устанавливаются через {@link FieldNode.updateComponentProps}.\\n *\\n * @example\\n * ```tsx\\n * // Установка props\\n * field.updateComponentProps({\\n * placeholder: \'Enter email...\',\\n * maxLength: 100,\\n * autoComplete: \'email\'\\n * });\\n *\\n * // Использование в компоненте\\n * const { componentProps, value } = useFormControl(field);\\n *\\n * return (\\n * <input\\n * value={value}\\n * placeholder={componentProps.placeholder}\\n * maxLength={componentProps.maxLength}\\n * autoComplete={componentProps.autoComplete}\\n * />\\n * );\\n * ```\\n */\\n componentProps: Record<string, unknown>;\\n\\n /**\\n * Флаг изменения поля.\\n * `true` когда значение поля отличается от начального.\\n *\\n * Реактивный аналог `control.dirty` — паритет с {@link ArrayControlState.dirty}.\\n *\\n * @example\\n * ```tsx\\n * const { dirty } = useFormControl(field);\\n *\\n * return dirty ? <span className=\\"badge\\">Изменено</span> : null;\\n * ```\\n */\\n dirty: boolean;\\n}","summary":"Состояние поля формы, возвращаемое хуком {@link useFormControl} для {@link FieldNode}.","description":"Состояние поля формы, возвращаемое хуком {@link useFormControl} для {@link FieldNode}.\\n\\nСодержит реактивные данные поля: значение, состояние валидации, флаги взаимодействия\\nи пользовательские props для компонентов.","params":[],"example":"Базовое использование\\n```tsx\\ninterface Props {\\ncontrol: FieldNode<string>;\\n}\\n\\nfunction TextField({ control }: Props) {\\nconst state = useFormControl(control);\\n\\nreturn (\\n<div>\\n<input\\nvalue={state.value}\\ndisabled={state.disabled}\\nonChange={e => control.setValue(e.target.value)}\\n/>\\n{state.shouldShowError && state.errors[0] && (\\n<span className=\\"error\\">{state.errors[0].message}</span>\\n)}\\n</div>\\n);\\n}\\n```","examplesCount":1,"related":["useFormControl","ArrayControlState"],"topics":["api-reference","complete-import"],"sourcePath":"src/platforms/react/hooks/types.ts","entries":["."],"package":"@reformer/core"},{"name":"FieldNode","kind":"class","signature":"export class FieldNode<T> extends FormNode<T> {\\n // ============================================================================\\n // Приватные сигналы\\n // ============================================================================ /* … */ }","summary":"FieldNode - узел для отдельного поля формы","description":"FieldNode - узел для отдельного поля формы","params":[],"example":"Пример node-level: конфиг УЗЛА, а не layout-схема M1 (в ней поля `validators` нет).\\n```typescript\\nconst field = new FieldNode({\\n value: \'\',\\n component: InputField,\\n validators: [required, email],\\n});\\n\\nfield.setValue(\'test@mail.com\');\\nawait field.validate();\\nconsole.log(field.valid.value); // true\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","complete-import","formschema","ui-components","type-safety-recipes"],"sourcePath":"src/form/nodes/field-node.ts","entries":["."],"package":"@reformer/core","usage":7},{"name":"FieldStatus","kind":"type","signature":"export type FieldStatus = \'valid\' | \'invalid\' | \'pending\' | \'disabled\';","summary":"Статус поля формы","description":"Статус поля формы","params":[],"examplesCount":0,"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"FileLike","kind":"interface","signature":"export interface FileLike {\\n name: string;\\n size?: number;\\n type?: string;\\n}","summary":"Минимальный файлоподобный контракт, с которым работают file-валидаторы: нативный `File`, сериализуемый дескриптор загруженного файла и т.п.","description":"Минимальный файлоподобный контракт, с которым работают file-валидаторы:\\nнативный `File`, сериализуемый дескриптор загруженного файла и т.п.","params":[],"examplesCount":0,"sourcePath":"src/form/validators/file-utils.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"fileType","kind":"function","signature":"export function fileType<TForm = unknown, TField = unknown>(\\n accept: string,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора типа файла.","description":"Фабрика валидатора типа файла.\\n\\nПроверяет каждый файл против accept-строки в синтаксисе нативного атрибута\\n`<input type=\\"file\\" accept>`: расширения (`.pdf`), точные MIME (`image/png`),\\nwildcard-категории (`image/*`), список через запятую. Матчинг регистронезависимый,\\nпо `type` и/или расширению из `name` ({@link matchesFileAccept}).\\n\\nНужен потому, что нативный `accept` — только подсказка пикеру: на drag-and-drop\\nи «All files» он не действует. Пустые значения (`null`/`undefined`/`\'\'`/`[]`)\\nпропускаются (используйте {@link required} для обязательности).","params":[["accept","- Accept-строка допустимых типов, например `\'image/*,.pdf\'`"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `accept` и `fileName` (первый нарушивший файл)."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Только изображения и PDF\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { fileType } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [fileType(\'image/*,.pdf\', { message: \'Только изображения или PDF\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/file-type.ts","entries":["./validators"],"package":"@reformer/core","usage":6},{"name":"FormArrayProxy","kind":"type","signature":"export type FormArrayProxy<T extends object> = ArrayNode<T> & {\\n /**\\n * Безопасный доступ к элементу массива по индексу\\n * Возвращает GroupNode с типизированными полями или undefined\\n */\\n at(index: number): FormProxy<T> | undefined;\\n\\n /**\\n * Итерация по элементам массива с типизированными элементами\\n */\\n forEach(callback: (item: FormProxy<T>, index: number) => void): void;\\n\\n /**\\n * Маппинг элементов массива с типизированными элементами\\n */\\n map<R>(callback: (item: FormProxy<T>, index: number) => R): R[];\\n};","summary":"Комбинированный тип для ArrayNode с Proxy доступом к элементам Объединяет методы и свойства ArrayNode с типизированным доступом к элементам массива.","description":"Комбинированный тип для ArrayNode с Proxy доступом к элементам\\n\\nОбъединяет методы и свойства ArrayNode с типизированным доступом к элементам массива.","params":[],"example":"```typescript\\ninterface TodoItem {\\n title: string;\\n completed: boolean;\\n}\\n\\nconst todos: FormArrayProxy<TodoItem> = new ArrayNode(schema);\\n\\n// Доступ к методам ArrayNode\\ntodos.push({ title: \'New todo\', completed: false });\\ntodos.removeAt(0);\\n\\n// Доступ к элементам (через Proxy)\\ntodos.at(0)?.title.setValue(\'Updated title\');\\n\\n// Итерация\\ntodos.forEach((item, i) => {\\n console.log(item.title.value.value);\\n});\\n```","examplesCount":1,"topics":["api-signatures"],"sourcePath":"src/form/types/form-proxy.ts","entries":["."],"package":"@reformer/core","usage":1},{"name":"FormBehavior","kind":"interface","signature":"export interface FormBehavior<T> {\\n /** @internal Запускается `createForm` после построения нод и заполнения реестра сигнал→нода. */\\n __run(model: FormModel<T>, form: FormProxy<T>): BehaviorCleanup;\\n}","summary":"Результат {@link defineFormBehavior}; передаётся в `createForm({ behavior })`.","description":"Результат {@link defineFormBehavior}; передаётся в `createForm({ behavior })`.","params":[],"examplesCount":0,"sourcePath":"src/form/behaviors/types.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"FormBundleLike","kind":"interface","signature":"export interface FormBundleLike {\\n validation?: { controller: FormValidationController };\\n}","summary":"Минимум, который хук ожидает от бандла: опциональный контроллер живой валидации.","description":"Минимум, который хук ожидает от бандла: опциональный контроллер живой валидации.","params":[],"examplesCount":0,"sourcePath":"src/platforms/react/hooks/use-form-bundle.ts","entries":["."],"package":"@reformer/core"},{"name":"FormControlsProxy","kind":"type","signature":"export type FormControlsProxy<T> = {\\n // `-?` снимает опциональность: для каждого поля схемы прокси всегда содержит узел\\n // (включая опциональные поля — у них узел существует, опционально лишь значение).\\n // Без этого `control.optionalField` имел бы тип `FieldNode<...> | undefined`.\\n [K in keyof T]-?: NonNullable<T[K]> extends ReadonlyArray<infer U>\\n ? IsGroupObject<U> extends true\\n ? FormArrayProxy<U & object> // Массив объектов → FormArrayProxy\\n : FieldNode<T[K]> // Массив примитивов → FieldNode\\n : IsGroupObject<NonNullable<T[K]>> extends true\\n ? FormProxy<NonNullable<T[K]>> // Обычный объект → FormProxy (рекурсивно!)\\n : FieldNode<T[K]>; // Примитивы и спец-объекты (Date/File/Blob) → FieldNode\\n};","summary":"Мапит тип модели данных T на правильные типы узлов формы Рекурсивно определяет типы узлов на основе структуры данных: - `T[K] extends Array<infer U>` где U - объект → `FormArrayProxy<U>` - `T[K] extends Array<infer U>` где U - примитив → `FieldNode<T[K]>` (массив как обычное поле) - `T[K] extends ob","description":"Мапит тип модели данных T на правильные типы узлов формы\\n\\nРекурсивно определяет типы узлов на основе структуры данных:\\n- `T[K] extends Array<infer U>` где U - объект → `FormArrayProxy<U>`\\n- `T[K] extends Array<infer U>` где U - примитив → `FieldNode<T[K]>` (массив как обычное поле)\\n- `T[K] extends object` → `FormProxy<T[K]>` (вложенная форма с типизацией)\\n- `T[K]` примитив → `FieldNode<T[K]>` (простое поле)\\n\\nИспользует NonNullable для правильной обработки опциональных полей","params":[],"examplesCount":0,"sourcePath":"src/form/types/form-proxy.ts","entries":["."],"package":"@reformer/core"},{"name":"FormErrorHandler","kind":"class","signature":"export class FormErrorHandler {\\n /**\\n * Обработать ошибку согласно заданной стратегии\\n *\\n * @param error Ошибка для обработки (Error | string | unknown)\\n * @param context Контекст ошибки для логирования (например, \'AsyncValidator\', \'BehaviorRegistry\')\\n * @param strategy Стратегия обработки (THROW | LOG | CONVERT)\\n * @returns ValidationError если strategy = CONVERT, undefined если strategy = LOG, никогда не возвращается если strategy = THROW\\n *\\n * @example\\n * ```typescript\\n * // THROW - пробросить ошибку\\n * try {\\n * riskyOperation();\\n * } catch (error) {\\n * FormErrorHandler.handle(error, \'RiskyOperation\', ErrorStrategy.THROW);\\n * // Этот код никогда не выполнится\\n * }\\n *\\n * // LOG - залогировать и продолжить\\n * try {\\n * nonCriticalOperation();\\n * } catch (error) {\\n * FormErrorHandler.handle(error, \'NonCritical\', ErrorStrategy.LOG);\\n * // Продолжаем выполнение\\n * }\\n *\\n * // CONVERT - конвертировать в ValidationError\\n * try {\\n * await validator(value);\\n * } catch (error) {\\n * const validationError = FormErrorHandler.handle(\\n * error,\\n * \'AsyncValidator\',\\n * ErrorStrategy.CONVERT\\n * );\\n * return validationError;\\n * }\\n * ```\\n */ /* … */ }","summary":"Централизованный обработчик ошибок для форм Обеспечивает: - Единообразное логирование ошибок в DEV режиме - Гибкие стратегии обработки (throw/log/convert) - Типобезопасное извлечение сообщений из Error/string/unknown","description":"Централизованный обработчик ошибок для форм\\n\\nОбеспечивает:\\n- Единообразное логирование ошибок в DEV режиме\\n- Гибкие стратегии обработки (throw/log/convert)\\n- Типобезопасное извлечение сообщений из Error/string/unknown","params":[],"example":"```typescript\\n// В async validator (конвертировать в ValidationError)\\ntry {\\n await validateEmail(value);\\n} catch (error) {\\n return FormErrorHandler.handle(error, \'EmailValidator\', ErrorStrategy.CONVERT);\\n}\\n\\n// В behavior applicator (пробросить критичную ошибку)\\ntry {\\n applyBehavior(schema);\\n} catch (error) {\\n FormErrorHandler.handle(error, \'BehaviorApplicator\', ErrorStrategy.THROW);\\n}\\n\\n// В validator (залогировать и продолжить)\\ntry {\\n validator(value);\\n} catch (error) {\\n FormErrorHandler.handle(error, \'Validator\', ErrorStrategy.LOG);\\n}\\n```","examplesCount":1,"sourcePath":"src/form/validation/error-handler.ts","entries":["."],"package":"@reformer/core"},{"name":"FormModel","kind":"type","signature":"export type FormModel<T> = ModelObject<T> & ModelApi<T>;","summary":"FormModel — под-модель объекта `T`: value-доступ ({@link ModelObject}) + `.$`-сигналы + {@link ModelApi} (get/set/patch/isDirty/reset/signalAt).","description":"FormModel — под-модель объекта `T`: value-доступ ({@link ModelObject}) + `.$`-сигналы + {@link ModelApi}\\n(get/set/patch/isDirty/reset/signalAt). Вложенные объекты-группы модели — тоже {@link FormModel}\\n(доступны как `model.<group>`), поэтому `model.<group>.$.<field>` эквивалентно `model.$.<group>.<field>`.","params":[],"examplesCount":0,"topics":["api-reference","quick-start","api-signatures","common-mistakes","complete-import","formschema","arrays","multi-step","project-structure","nonexistent-api","conditional-fields","reading-values","array-operations","submit-and-reset","async-preload","type-safety-recipes","validation-strategy"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core","usage":52},{"name":"FormNode","kind":"class","signature":"export abstract class FormNode<T> {\\n // ============================================================================\\n // Protected состояние (для Template Method паттерна)\\n // ============================================================================\\n\\n /**\\n * Пользователь взаимодействовал с узлом (touched)\\n * Protected: наследники могут читать/изменять через методы\\n */ /* … */ }","summary":"Абстрактный базовый класс для всех узлов формы.","description":"Абстрактный базовый класс для всех узлов формы.\\n\\nВсе узлы (поля, группы, массивы) наследуют от этого класса и реализуют\\nединый интерфейс для работы с состоянием и валидацией.\\n\\nTemplate Method паттерн используется для управления состоянием:\\nобщие signals (`_touched`, `_dirty`, `_status`) живут в базовом классе,\\npubli-методы (`markAsTouched`, `disable`, …) реализованы здесь, а protected\\nhooks (`onMarkAsTouched`, `onDisable`, …) переопределяются в наследниках.","params":[],"example":"```typescript\\n// FormNode не используется напрямую — экземпляры приходят из getReformerForm.\\nimport { getReformerForm, FormNode } from \'@reformer/core\';\\n\\nconst form = getReformerForm({ email: \'\' });\\nform.email instanceof FormNode; // true\\nform.email.markAsTouched();\\n```","examplesCount":1,"sourcePath":"src/form/nodes/form-node.ts","entries":["."],"package":"@reformer/core"},{"name":"FormProxy","kind":"type","signature":"export type FormProxy<T> = GroupNode<T> &\\n // Исключаем имена, совпадающие с членами GroupNode: для них `form.<name>` возвращает член узла,\\n // а не поле. Оставлять их в полевом пространстве — значит пересекать, напр., ReadonlySignal<FieldStatus>\\n // с FieldNode<string> и молча компилировать невозможный тип. Escape-hatch — `form.$` ниже.\\n Omit<FormControlsProxy<T>, keyof GroupNode<T>> & {\\n /**\\n * Escape-hatch пространство имён «controls»: типобезопасный доступ ко ВСЕМ полям формы\\n * по имени, включая поля, чьи имена совпадают с членами {@link GroupNode}\\n * (`value`/`status`/`id`/`errors`/…), недостижимые через `form.<name>`.\\n *\\n * @example\\n * ```typescript\\n * // модель: { status: string; email: string }\\n * form.status; // ReadonlySignal<FieldStatus> — агрегат GroupNode (не поле!)\\n * form.$.status; // FieldNode<string> — поле пользователя\\n * form.$.status.setValue(\'active\');\\n * form.$.email; // FieldNode<string> — так же доступны и незатенённые поля\\n * ```\\n */\\n readonly $: FormControlsProxy<T>;\\n };","summary":"Комбинированный тип для GroupNode с Proxy доступом к полям Объединяет методы и свойства GroupNode с типизированными полями формы.","description":"Комбинированный тип для GroupNode с Proxy доступом к полям\\n\\nОбъединяет методы и свойства GroupNode с типизированными полями формы.\\nЭто позволяет использовать как API GroupNode, так и прямой доступ к полям.","params":[],"example":"```typescript\\ninterface UserForm {\\n email: string;\\n profile: {\\n name: string;\\n age: number;\\n };\\n}\\n\\nconst form = createForm<UserForm>(schema);\\n\\n// Доступ к методам GroupNode\\nawait form.validate();\\nconst values = form.getValue();\\nconsole.log(form.valid.value);\\n\\n// Прямой доступ к полям (через Proxy)\\nform.email.setValue(\'test@mail.com\');\\nform.profile.name.setValue(\'John\');\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-mistakes","complete-import","formschema","arrays","array-operations","async-preload","type-safety-recipes"],"sourcePath":"src/form/types/form-proxy.ts","entries":["."],"package":"@reformer/core","usage":57},{"name":"FormSchema","kind":"type","signature":"export type FormSchema<T> = {\\n // Листовые позиции используют NonEmptyFieldConfig: пустой `{}` (частая опечатка) отклоняется\\n // на этапе компиляции, но каждое свойство FieldConfig по отдельности остаётся опциональным.\\n [K in keyof T]: NonNullable<T[K]> extends string | number | boolean\\n ? NonEmptyFieldConfig<T[K]>\\n : NonNullable<T[K]> extends Array<infer U>\\n ? U extends string | number | boolean\\n ? NonEmptyFieldConfig<T[K]>\\n : U extends Date | File | Blob | AnyFunction\\n ? NonEmptyFieldConfig<T[K]>\\n : [FormSchema<U>]\\n : NonNullable<T[K]> extends Date | File | Blob | AnyFunction\\n ? NonEmptyFieldConfig<T[K]>\\n : FormSchema<NonNullable<T[K]>>;\\n};","summary":"**Data-shaped** конфиг формы: ключи повторяют структуру данных `T`, значения — {@link FieldConfig} (или вложенный `FormSchema`).","description":"**Data-shaped** конфиг формы: ключи повторяют структуру данных `T`, значения — {@link FieldConfig}\\n(или вложенный `FormSchema`). Форма конфига, из которой строится {@link GroupNode}.\\n- `T[] -> [FormSchema<T>]` (массив с одним элементом)\\n- `object -> FormSchema<T>` (группа)\\n- `primitive -> FieldConfig<T>` (поле)\\n\\nИспользует NonNullable для корректной обработки опциональных полей.\\n\\n⚠️ Не путать с {@link FormSchemaNode} — тот описывает **узел дерева** M1-схемы (лист/массив/\\nконтейнер), передаваемой в `createForm({ model, schema })`. `FormSchema` — это data-shaped конфиг\\n(ключи = поля данных), а не узел дерева.","params":[],"example":"```typescript\\ninterface Form {\\n name: string; // → FieldConfig<string>\\n address: { // → FormSchema<Address>\\n city: string;\\n street: string;\\n };\\n items?: Array<{ // → [FormSchema<Item>] (опциональный)\\n title: string;\\n price: number;\\n }>;\\n}\\n\\nconst schema: FormSchema<Form> = {\\n name: { value: \'\', component: InputField },\\n address: {\\n city: { value: \'\', component: InputField },\\n street: { value: \'\', component: InputField },\\n },\\n items: [{\\n title: { value: \'\', component: InputField },\\n price: { value: 0, component: InputField },\\n }],\\n};\\n```","examplesCount":1,"topics":["api-reference","complete-import","formschema","project-structure"],"sourcePath":"src/form/types/deep-schema.ts","entries":["."],"package":"@reformer/core","usage":1},{"name":"FormSchemaNode","kind":"interface","signature":"export interface FormSchemaNode {\\n /**\\n * «Ручка» значения поля — маркер узла-поля. Обычно сигнал модели (`model.$.<path>`), но форма\\n * зависит от таргета (для массива `model.$.x` — дерево сигналов; в renderer-типах сужается до\\n * `Signal`). Движок разбирает узел как поле рантаймом по `value instanceof Signal`.\\n */\\n value?: unknown;\\n /**\\n * UI-компонент либо нативный HTML-тег (`\'div\'`, `\'p\'`, `\'h3\'`) для презентационной вёрстки\\n * прямо в схеме. Опционален: core-часть работает без UI (значение/валидация) и `component`\\n * не интерпретирует — он доезжает до рендерера как есть.\\n */\\n component?: ElementType;\\n /** Props компонента. Также «клапан» для вложенности под-узлов (напр. steps визарда). */\\n componentProps?: Record<string, unknown>;\\n updateOn?: \'change\' | \'blur\' | \'submit\';\\n disabled?: boolean;\\n /** Задержка (мс) перед запуском асинхронной валидации. */\\n debounce?: number;\\n /** Идентификатор узла (для wizard/tabs/renderBehavior). */\\n selector?: string;\\n /**\\n * ⚠️ Рантайм этого поля НЕ ЧИТАЕТ — `renderer-react` берёт testId из `componentProps.testId`\\n * (иначе выводит из пути сигнала). Поле оставлено только потому, что `RenderSchemaNode`\\n * рендерера объявляет свой одноимённый; пишите `componentProps: { testId: \'…\' }`.\\n */\\n testId?: string;\\n /**\\n * Содержимое узла: под-узлы (даёт контекстную типизацию вложенным литералам — value/validators/when)\\n * и текстовые части. Текст (литерал, число, сигнал модели) — такой же ребёнок, как узел: core его\\n * не интерпретирует (обход пропускает примитивы и не спускается внутрь сигнала), а рендерер\\n * выводит на своём месте в порядке следования.\\n */\\n children?: readonly (FormSchemaNode | string | number | Signal<any>)[];\\n /** Реактивный массив модели (`model.<path>`) — маркер узла-массива (вместе с `item`). */\\n array?: SchemaArrayControl;\\n /** Схема элемента массива: под-модель элемента → узел поддерева. */\\n item?: (itemModel: any) => FormSchemaNode;\\n /**\\n * Значение нового элемента массива для кнопки «Добавить»: либо готовое значение,\\n * либо фабрика `() => value`. Тип не различает варианты (union `unknown | (() => unknown)`\\n * схлопывается в `unknown`) — рантайм различает по `typeof initialValue === \'function\'`.\\n */\\n initialValue?: unknown;\\n /** Свободная вложенность: record-of-fields и произвольные под-узлы. */\\n [key: string]: unknown;\\n}","summary":"Узел единой схемы M1 — layout-дерево, обходимое `createForm({ model, schema })` и рендерерами (schema-валидация живёт отдельно — `@reformer/core/validation`).","description":"Узел единой схемы M1 — layout-дерево, обходимое `createForm({ model, schema })`\\nи рендерерами (schema-валидация живёт отдельно — `@reformer/core/validation`).\\n\\nУзел совмещает несколько ролей (различаются рантаймом по форме):\\n - **поле** — несёт `value: Signal` (сигнал модели `model.$.x`) + `component`/`validators`;\\n - **массив** — `{ array: model.<path>, item(itemModel) }`;\\n - **контейнер/ветка** — вложенные узлы (`children`), опц. условие `when`;\\n - **record-of-fields** — под-узлы под произвольными именованными ключами (индексная сигнатура).\\n\\nИндексная сигнатура (`[key: string]: unknown`) отражает свободный рекурсивный обход: под-узлы\\nдопустимы под любым ключом. Известные поля типизированы (даёт автокомплит и проверку их типов).","params":[],"examplesCount":0,"sourcePath":"src/form/types/schema-node.ts","entries":["."],"package":"@reformer/core"},{"name":"FormSubmitter","kind":"class","signature":"export class FormSubmitter<T extends object> {\\n /** Внутренний сигнал состояния отправки */ /* … */ }","summary":"FormSubmitter - управляет процессом отправки формы","description":"FormSubmitter - управляет процессом отправки формы","params":[],"example":"```typescript\\nconst submitter = new FormSubmitter(form);\\n\\n// Простой submit\\nconst result = await submitter.submit(async (values) => {\\n return await api.saveForm(values);\\n});\\n\\n// Проверка состояния\\nif (submitter.submitting.value) {\\n console.log(\'Форма отправляется...\');\\n}\\n```","examplesCount":1,"sourcePath":"src/form/form-submitter.ts","entries":["."],"package":"@reformer/core"},{"name":"FormValidation","kind":"interface","signature":"export interface FormValidation<T> {\\n /** Полный набор правил — для submit и `validateAll`. Без него собирается из `steps` + `extras`. */\\n schema?: ValidationSchema<T>;\\n /**\\n * Пошаговая валидация визарда: ключ = `selector` шага. `null` означает «шаг без правил» ЯВНО —\\n * чтобы опечатка в ключе не выглядела как пустой шаг.\\n */\\n steps?: Record<string, ValidationSchema<T> | null>;\\n /** Cross-field правила, которые проверяются только целиком (в `validateAll`), но не по шагам. */\\n extras?: ValidationSchema<T>;\\n /** Когда запускать живую валидацию. По умолчанию `\'submit\'` (реактивно молчит). */\\n strategy?: ValidationStrategyKind;\\n debounce?: number;\\n /** Режим live-фазы для `afterFirstSubmit`. По умолчанию `\'change\'`. */\\n liveAfterSubmit?: \'change\' | \'blur\';\\n}","summary":"Правила валидации формы — ДАННЫЕ (без привязки к рендеру).","description":"Правила валидации формы — ДАННЫЕ (без привязки к рендеру).\\n\\n⚠️ `schema` и значения `steps` обязаны быть **стабильными ссылками**: отмена устаревших прогонов\\nключуется по паре `(model, schema)` через `WeakMap`, поэтому инлайн-стрелка ломает дедупликацию —\\nвалидация начнёт возвращать `false` от уже отменённых прогонов. Держите их\\nmodule-level-константами (`defineValidationSchema`).","params":[],"examplesCount":0,"sourcePath":"src/form/validation/config.ts","entries":["."],"package":"@reformer/core","usage":2},{"name":"FormValidationBundle","kind":"interface","signature":"export interface FormValidationBundle<T> {\\n /** Полная схема (стабильная ссылка) — та, по которой идёт `validateAll`. */\\n readonly schema: ValidationSchema<T>;\\n /** Селекторы шагов в порядке объявления. Пусто, если `steps` не заданы. */\\n readonly stepSelectors: readonly string[];\\n /** Полный прогон с раскрытием ошибок. Синоним {@link FormValidationBundle.validateAll}. */\\n validate(): Promise<boolean>;\\n validateAll(): Promise<boolean>;\\n /** Прогон правил одного шага: по номеру (1-based, как у визарда) или по селектору. */\\n validateStep(step: number | string): Promise<boolean>;\\n /** Контроллер живой валидации ШАГА; `null` — у шага нет правил либо стратегия `submit`. */\\n createStepController(step: number | string): FormValidationController | null;\\n /** Контроллер живой валидации ФОРМЫ. Армится хуком (`useFormBundle`), не фабрикой. */\\n readonly controller: FormValidationController;\\n /** Идёт ли прогон — реактивный сигнал (для тонкой подписки в UI). */\\n readonly validating: ReadonlySignal<boolean>;\\n}","summary":"Собранная валидация формы.","description":"Собранная валидация формы. Структурно совместима с `FormWizardConfig` и `StepValidationConfig`\\nиз `@reformer/cdk`, поэтому уходит в визард как есть: `config={bundle.validation}` либо\\n`patchProps({ form, ...bundle.validation })`.","params":[],"examplesCount":0,"sourcePath":"src/form/validation/config.ts","entries":["."],"package":"@reformer/core","usage":4},{"name":"FormValidationController","kind":"interface","signature":"export interface FormValidationController {\\n /**\\n * Полный прогон схемы с раскрытием ошибок (`touch: true`) — для submit. Также переводит\\n * `afterFirstSubmit` в live-фазу. Возвращает `false`, если есть блокирующие ошибки.\\n */\\n validate(): Promise<boolean>;\\n /**\\n * Армировать реактивные подписки стратегии. Идемпотентно. Возвращает `dispose`. НЕ звать при SSR.\\n *\\n * После {@link FormValidationController.dispose} контроллер армируется ЗАНОВО: React монтирует\\n * компоненты повторно (StrictMode в разработке, remount по роуту), и «одноразовый» контроллер\\n * после такого цикла молча оставался бы без живой валидации.\\n */\\n start(): () => void;\\n /** Снять подписки/таймеры. Идемпотентно; после него `start()` снова армирует стратегию. */\\n dispose(): void;\\n /** Идёт ли прогон (submit или live) — снапшот. */\\n readonly isValidating: boolean;\\n /** Реактивный сигнал состояния прогона (для тонкой подписки в UI). */\\n readonly validating: ReadonlySignal<boolean>;\\n}","summary":"","params":[],"examplesCount":0,"topics":["validation-strategy"],"sourcePath":"src/form/validation/strategy.ts","entries":["./validation"],"package":"@reformer/core"},{"name":"FormValue","kind":"type","signature":"export type FormValue =\\n | string\\n | number\\n | boolean\\n | null\\n | undefined\\n | Date\\n | File\\n | FormValue[]\\n | { [key: string]: FormValue };","summary":"Represents any valid form value type Use this instead of \'any\' for form values to maintain type safety","description":"Represents any valid form value type\\nUse this instead of \'any\' for form values to maintain type safety","params":[],"examplesCount":0,"topics":["common-mistakes","complete-import","arrays","type-safety-recipes"],"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"futureDate","kind":"function","signature":"export function futureDate<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что дата не в прошлом.","description":"Фабрика валидатора, проверяющего что дата не в прошлом.\\n\\nДата не должна быть раньше сегодняшнего дня (сравнение по нормализованным датам).\\nПустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для поля даты (`string | Date`)","example":"Дата не в прошлом\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, futureDate } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.appointmentDate, [required(), futureDate({ message: \'Дата записи должна быть в будущем\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/future-date.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"getNodeForSignal","kind":"function","signature":"export function getNodeForSignal(signal: Signal<any>): FormNode<any> | undefined","summary":"Найти ноду формы по сигналу модели.","description":"Найти ноду формы по сигналу модели.\\n\\nИспользуется state-операциями behavior (`enableWhen`/`disableWhen`) и роутингом ошибок\\nвалидации в ноды. Возвращает `undefined`, если форма ещё не построена или поле не\\nматериализовано в этой форме (например, элемент массива, который строится per-item).","params":[["signal","- Сигнал значения из {@link FormModel}"]],"returns":"Нода формы для этого поля или `undefined`","example":"Роутинг ошибок валидации в ноду поля\\n```typescript\\nimport { getNodeForSignal } from \'@reformer/core\';\\n\\nconst sig = model.$.email;\\ngetNodeForSignal(sig)?.setErrors([{ code: \'required\', message: \'Обязательно\' }]);\\n```","examplesCount":1,"related":["registerSignalNode"],"topics":["api-signatures","multi-step","revalidate-when","async-validator-debounce"],"sourcePath":"src/form/signal-node-registry.ts","entries":["."],"package":"@reformer/core","usage":5},{"name":"getNodeType","kind":"function","signature":"export function getNodeType(node: unknown): string","summary":"Получить тип узла как строку (для отладки) Полезно для логирования и отладки","description":"Получить тип узла как строку (для отладки)\\n\\nПолезно для логирования и отладки","params":[["node","- Узел для проверки"]],"returns":"Строковое название типа узла","example":"```typescript\\nconsole.log(\'Node type:\', getNodeType(node)); // \\"FieldNode\\" | \\"GroupNode\\" | \\"ArrayNode\\" | \\"FormNode\\" | \\"Unknown\\"\\n```","examplesCount":1,"sourcePath":"src/form/type-guards.ts","entries":["."],"package":"@reformer/core"},{"name":"getScope","kind":"function","signature":"export function getScope<T>(): BehaviorScope<T>","summary":"Текущий scope ({ model, form }) активной схемы (escape hatch для кросс-операторов).","description":"Текущий scope ({ model, form }) активной схемы (escape hatch для кросс-операторов).","params":[],"examplesCount":0,"topics":["api-reference"],"sourcePath":"src/form/behaviors/context.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"GroupNode","kind":"class","signature":"export class GroupNode<T> extends FormNode<T> {\\n // ============================================================================\\n // Приватные поля\\n // ============================================================================ /* … */ }","summary":"GroupNode - узел для группы полей Создаётся из {@link FormSchema} (дерево field-конфигов).","description":"GroupNode - узел для группы полей\\n\\nСоздаётся из {@link FormSchema} (дерево field-конфигов). Обычно строится через `createForm`\\n(M1: `createForm({ model, schema })`); schema-валидация/behavior живут на слое модели\\n(`validateModel` из `@reformer/core/validation`, `computeFrom`/`enableWhen`/…), а не на ноде.","params":[],"example":"```typescript\\nconst form = new GroupNode({\\n email: { valueSignal: model.$.email, component: InputField },\\n password: { valueSignal: model.$.password, component: InputField },\\n});\\n\\n// Прямой доступ к полям через Proxy\\nconst proxy = form.getProxy();\\nproxy.email.setValue(\'test@mail.com\');\\nawait proxy.validate();\\nconsole.log(proxy.valid.value);\\n```","examplesCount":1,"topics":["api-reference","api-signatures","complete-import"],"sourcePath":"src/form/nodes/group-node.ts","entries":["."],"package":"@reformer/core","usage":4},{"name":"GroupNodeConfig","kind":"interface","signature":"export interface GroupNodeConfig<T> {\\n /** Схема структуры формы (поля и их конфигурация) */\\n form: FormSchema<T>;\\n}","summary":"Конфигурация GroupNode.","description":"Конфигурация GroupNode.\\n\\nПод M1 группа создаётся из плоской {@link FormSchema} (дерево field-конфигов). Обёртка\\n`{ form }` сохранена для совместимости вызова, legacy behavior/validation-схемы удалены (Ф7).","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"integer","kind":"function","signature":"export function integer<TForm = unknown, TField extends number | null | undefined = number>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что число — целое.","description":"Фабрика валидатора, проверяющего что число — целое.\\n\\nПустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Проверка целого числа\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, integer } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.count, [required(), integer({ message: \'Должно быть целым числом\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/integer.ts","entries":["./validators"],"package":"@reformer/core","usage":3},{"name":"isArrayNode","kind":"function","signature":"export function isArrayNode(value: unknown): value is ArrayNode<object>","summary":"Проверить, является ли значение ArrayNode (массив форм) ArrayNode представляет массив вложенных форм (обычно GroupNode) и имеет array-like методы (push, removeAt, at)","description":"Проверить, является ли значение ArrayNode (массив форм)\\n\\nArrayNode представляет массив вложенных форм (обычно GroupNode)\\nи имеет array-like методы (push, removeAt, at)","params":[["value","- Значение для проверки"]],"returns":"true если value является ArrayNode","example":"```typescript\\nif (isArrayNode(node)) {\\n node.push(); // OK - добавить элемент\\n node.removeAt(0); // OK - удалить элемент\\n const item = node.at(0); // OK - получить элемент\\n}\\n```","examplesCount":1,"topics":["common-mistakes","formschema"],"sourcePath":"src/form/type-guards.ts","entries":["."],"package":"@reformer/core"},{"name":"isDate","kind":"function","signature":"export function isDate<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что значение — валидная дата.","description":"Фабрика валидатора, проверяющего что значение — валидная дата.\\n\\nПринимает `Date` или строку, парсимую в дату. Пустые значения (`\'\'`/`null`/`undefined`)\\nпропускаются (используйте {@link required} для обязательности).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для поля даты (`string | Date`)","example":"Проверка валидности даты\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, isDate } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.eventDate, [required(), isDate({ message: \'Введите корректную дату\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/is-date.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"isDerived","kind":"function","signature":"export function isDerived(signal: Signal<any>): boolean","summary":"Производный ли сигнал (помечен через {@link markDerived}).","description":"Производный ли сигнал (помечен через {@link markDerived}).\\n\\nЧитается bulk-сеттерами модели/группы, чтобы не затирать вычисляемые (`computeFrom`) поля\\nзначениями из payload.","params":[["signal","- Сигнал значения из {@link FormModel}"]],"returns":"`true`, если сигнал помечен производным","example":"```typescript\\nimport { isDerived } from \'@reformer/core\';\\n\\nif (!isDerived(model.$.total)) {\\n model.$.total.value = payload.total; // писать в payload-значение только для «ручных» полей\\n}\\n```","examplesCount":1,"related":["markDerived"],"sourcePath":"src/model/derived-registry.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"isFieldNode","kind":"function","signature":"export function isFieldNode(value: unknown): value is FieldNode<FormValue>","summary":"Проверить, является ли значение FieldNode (примитивное поле) FieldNode представляет примитивное поле формы (string, number, boolean и т.д.) и имеет валидаторы, но не имеет вложенных полей или элементов массива","description":"Проверить, является ли значение FieldNode (примитивное поле)\\n\\nFieldNode представляет примитивное поле формы (string, number, boolean и т.д.)\\nи имеет валидаторы, но не имеет вложенных полей или элементов массива","params":[["value","- Значение для проверки"]],"returns":"true если value является FieldNode","example":"```typescript\\nif (isFieldNode(node)) {\\n node.validators; // OK\\n node.asyncValidators; // OK\\n node.markAsTouched(); // OK\\n}\\n```","examplesCount":1,"topics":["common-mistakes","formschema"],"sourcePath":"src/form/type-guards.ts","entries":["."],"package":"@reformer/core"},{"name":"isFileLike","kind":"function","signature":"export function isFileLike(value: unknown): value is FileLike","summary":"Проверяет, что значение файлоподобно: объект со строковым `name` и опциональными числовым `size` / строковым `type`.","description":"Проверяет, что значение файлоподобно: объект со строковым `name` и опциональными\\nчисловым `size` / строковым `type`.","params":[["value","- Проверяемое значение"]],"returns":"`true`, если значение соответствует {@link FileLike}","examplesCount":0,"sourcePath":"src/form/validators/file-utils.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"isFormNode","kind":"function","signature":"export function isFormNode(value: unknown): value is FormNode<FormValue>","summary":"Проверить, является ли значение любым FormNode Проверяет базовые свойства, общие для всех типов узлов","description":"Проверить, является ли значение любым FormNode\\n\\nПроверяет базовые свойства, общие для всех типов узлов","params":[["value","- Значение для проверки"]],"returns":"true если value является FormNode","example":"```typescript\\nif (isFormNode(value)) {\\n value.setValue(newValue);\\n value.validate();\\n}\\n```","examplesCount":1,"sourcePath":"src/form/type-guards.ts","entries":["."],"package":"@reformer/core"},{"name":"isGroupNode","kind":"function","signature":"export function isGroupNode(value: unknown): value is GroupNode<object>","summary":"Проверить, является ли значение GroupNode (объект с вложенными полями) GroupNode представляет объект с вложенными полями формы: имеет навигацию по полям (`getFieldByPath`/`fields`) и НЕ имеет array-методов (`items`/`push`/`removeAt`).","description":"Проверить, является ли значение GroupNode (объект с вложенными полями)\\n\\nGroupNode представляет объект с вложенными полями формы: имеет навигацию по полям\\n(`getFieldByPath`/`fields`) и НЕ имеет array-методов (`items`/`push`/`removeAt`).","params":[["value","- Значение для проверки"]],"returns":"true если value является GroupNode","example":"```typescript\\nif (isGroupNode(node)) {\\n node.getFieldByPath(\'user.email\'); // OK\\n}\\n```","examplesCount":1,"topics":["common-mistakes","formschema"],"sourcePath":"src/form/type-guards.ts","entries":["."],"package":"@reformer/core"},{"name":"isModelContainerSignal","kind":"function","signature":"export function isModelContainerSignal(value: unknown): boolean","summary":"Узел дерева `model.$` — контейнер (группа/массив), а не лист?","description":"Узел дерева `model.$` — контейнер (группа/массив), а не лист?\\n\\nКонтейнерный узел структурно совместим с `ReadonlySignal` (`peek`/`value`/`subscribe`), поэтому\\nduck-typing «есть `peek` ⇒ это лист» на нём даёт ложное срабатывание. Этот guard — надёжный\\nспособ различить: обходчикам дерева нужно спускаться в контейнер, а не читать его целиком.","params":[],"example":"```typescript\\nconst isLeaf = (v: unknown) => isSignalLike(v) && !isModelContainerSignal(v);\\n```","examplesCount":1,"sourcePath":"src/model/model-signals-proxy.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"isNumber","kind":"function","signature":"export function isNumber<TForm = unknown, TField extends number | null | undefined = number>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что значение — конечное число (не NaN, не строка).","description":"Фабрика валидатора, проверяющего что значение — конечное число (не NaN, не строка).\\n\\nПустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для\\nобязательности). В отличие от других number-валидаторов, **не** пропускает не-числа\\nи `NaN` — это его задача.","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Проверка, что значение — число\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, isNumber } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.amount, [required(), isNumber({ message: \'Введите число\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/is-number.ts","entries":["./validators"],"package":"@reformer/core","usage":3},{"name":"markDerived","kind":"function","signature":"export function markDerived(signal: Signal<any>): void","summary":"Пометить сигнал производным (вычисляемым).","description":"Пометить сигнал производным (вычисляемым).\\n\\nВызывается операторами {@link computeFrom}/`compute` для их сигнала-цели. После этого\\nbulk-сеттеры (`model.set`/`model.patch`, `patchValue`/`setValue`) пропускают это поле, чтобы\\nзначение из payload не затирало вычисляемое. Прикладной код напрямую обычно не вызывает.\\n\\nИдемпотентна на уровне флага: повторные вызовы наращивают счётчик ссылок, чтобы каждый оператор,\\nпишущий в этот сигнал, был сбалансирован своим {@link unmarkDerived} при dispose.","params":[["signal","- Сигнал значения из {@link FormModel}, которым владеет compute"]],"example":"```typescript\\nimport { markDerived } from \'@reformer/core\';\\n\\n// Помечаем поле total как вычисляемое — bulk-set его не перезапишет\\nmarkDerived(model.$.total);\\n```","examplesCount":1,"related":["isDerived","unmarkDerived"],"sourcePath":"src/model/derived-registry.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"matchesFileAccept","kind":"function","signature":"export function matchesFileAccept(file: Pick<FileLike, \'name\' | \'type\'>, accept: string): boolean","summary":"Проверяет файл против accept-паттерна в синтаксисе нативного атрибута `<input type=\\"file\\" accept>`: список через запятую из расширений (`.pdf`), точных MIME (`image/png`) и wildcard-категорий (`image/*`).","description":"Проверяет файл против accept-паттерна в синтаксисе нативного атрибута\\n`<input type=\\"file\\" accept>`: список через запятую из расширений (`.pdf`),\\nточных MIME (`image/png`) и wildcard-категорий (`image/*`). Регистронезависимо.\\n\\nНужен собственный матчер, потому что `accept` у нативного input — только подсказка\\nпикеру: на drag-and-drop и на программное значение он не действует.","params":[["file","- Файлоподобное значение (`name` + опциональный `type`)"],["accept","- Accept-строка; пустая/пробельная строка матчит всё"]],"returns":"`true`, если файл подходит хотя бы под один паттерн","examplesCount":0,"sourcePath":"src/form/validators/file-utils.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"max","kind":"function","signature":"export function max<TForm = unknown, TField extends number | null | undefined = number>(\\n maxValue: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора максимального числового значения.","description":"Фабрика валидатора максимального числового значения.\\n\\nПустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).","params":[["maxValue","- Максимально допустимое значение (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `max` и `actual`."]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Максимальное значение числового поля\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, max } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.quantity, [max(100)]);\\nvalidate(model.$.discount, [required(), max(50, { message: \'Не более 50%\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","complete-import","form-types","revalidate-when","type-safety-recipes"],"sourcePath":"src/form/validators/max.ts","entries":["./validators"],"package":"@reformer/core","usage":25},{"name":"maxAge","kind":"function","signature":"export function maxAge<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(maxAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора максимального возраста (по дате рождения).","description":"Фабрика валидатора максимального возраста (по дате рождения).\\n\\nВозраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные\\nдаты пропускаются (используйте {@link required} и {@link isDate}).","params":[["maxAgeValue","- Максимально допустимый возраст (в полных годах)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `maxAge` и `currentAge`."]],"returns":"Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)","example":"Максимальный возраст\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxAge } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.birthDate, [maxAge(100, { message: \'Проверьте дату рождения\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","type-safety-recipes"],"sourcePath":"src/form/validators/max-age.ts","entries":["./validators"],"package":"@reformer/core","usage":3},{"name":"maxDate","kind":"function","signature":"export function maxDate<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(maxDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора максимальной даты (включительно).","description":"Фабрика валидатора максимальной даты (включительно).\\n\\nСравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты\\nпропускаются (используйте {@link required} и {@link isDate}).","params":[["maxDateValue","- Максимально допустимая дата (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадает `maxDate`."]],"returns":"Чистый валидатор {@link Validator} для поля даты (`string | Date`)","example":"Максимальная дата\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxDate } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.birthDate, [maxDate(new Date(), { message: \'Дата не может быть в будущем\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","type-safety-recipes"],"sourcePath":"src/form/validators/max-date.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"maxFiles","kind":"function","signature":"export function maxFiles<TForm = unknown, TField = unknown>(\\n max: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора максимального количества файлов.","description":"Фабрика валидатора максимального количества файлов.\\n\\nРаботает с массивом файлов (одиночный файл считается как 1). Пустые значения\\n(`null`/`undefined`/`\'\'`/`[]`) пропускаются (используйте {@link required}\\nдля обязательности).","params":[["max","- Максимально допустимое количество файлов (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `maxFiles` и `actualCount`."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Не более трёх вложений\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxFiles } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [maxFiles(3, { message: \'Максимум 3 файла\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/max-files.ts","entries":["./validators"],"package":"@reformer/core","usage":16},{"name":"maxFileSize","kind":"function","signature":"export function maxFileSize<TForm = unknown, TField = unknown>(\\n maxSize: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора максимального размера файла.","description":"Фабрика валидатора максимального размера файла.\\n\\nРаботает с одиночным файлом или массивом (`File` либо файлоподобный дескриптор с\\n`name`/`size`). Проверяется каждый файл; в ошибку попадает первый нарушивший.\\nПустые значения (`null`/`undefined`/`\'\'`/`[]`) и элементы без числового `size`\\n(например, дескриптор загруженного файла без размера) пропускаются\\n(используйте {@link required} для обязательности).","params":[["maxSize","- Максимально допустимый размер файла в байтах (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `maxFileSize`, `fileName` и `actualSize`."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Ограничение размера вложений\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxFileSize } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [maxFileSize(5 * 1024 * 1024, { message: \'Файл больше 5 МБ\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/max-file-size.ts","entries":["./validators"],"package":"@reformer/core","usage":13},{"name":"maxLength","kind":"function","signature":"export function maxLength<TForm = unknown, TField = unknown>(\\n maxLen: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора максимальной длины строки или массива.","description":"Фабрика валидатора максимальной длины строки или массива.\\n\\nРаботает со строкой или массивом (проверяется `value.length`). Пустые значения\\n(`null`/`undefined`/`\'\'`) и значения без числового `length` пропускаются\\n(используйте {@link required} для обязательности).","params":[["maxLen","- Максимально допустимая длина (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `maxLength` и `actualLength`."]],"returns":"Чистый валидатор {@link Validator} для строки или массива","example":"Максимальная длина строки\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxLength } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.name, [maxLength(50)]);\\nvalidate(model.$.bio, [maxLength(500, { message: \'Максимум 500 символов\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","type-safety-recipes"],"sourcePath":"src/form/validators/max-length.ts","entries":["./validators"],"package":"@reformer/core","usage":30},{"name":"maxTotalFileSize","kind":"function","signature":"export function maxTotalFileSize<TForm = unknown, TField = unknown>(\\n maxTotal: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора суммарного размера всех файлов.","description":"Фабрика валидатора суммарного размера всех файлов.\\n\\nСкладывает `size` всех файлов значения (элементы без числового `size` в сумму\\nне входят). Пустые значения (`null`/`undefined`/`\'\'`/`[]`) пропускаются\\n(используйте {@link required} для обязательности).","params":[["maxTotal","- Максимально допустимый суммарный размер в байтах (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `maxTotalFileSize` и `actualTotal`."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Суммарно не более 20 МБ\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { maxTotalFileSize } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [maxTotalFileSize(20 * 1024 * 1024, { message: \'Суммарно не более 20 МБ\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/max-total-file-size.ts","entries":["./validators"],"package":"@reformer/core","usage":2},{"name":"min","kind":"function","signature":"export function min<TForm = unknown, TField extends number | null | undefined = number>(\\n minValue: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора минимального числового значения.","description":"Фабрика валидатора минимального числового значения.\\n\\nПустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).","params":[["minValue","- Минимально допустимое значение (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `min` и `actual`."]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Минимальное значение числового поля\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, min } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.age, [min(18)]);\\nvalidate(model.$.quantity, [required(), min(1, { message: \'Минимум 1\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","form-types","arrays","multi-step","nonexistent-api","conditional-fields","type-safety-recipes"],"sourcePath":"src/form/validators/min.ts","entries":["./validators"],"package":"@reformer/core","usage":54},{"name":"minAge","kind":"function","signature":"export function minAge<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(minAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора минимального возраста (по дате рождения).","description":"Фабрика валидатора минимального возраста (по дате рождения).\\n\\nВозраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные\\nдаты пропускаются (используйте {@link required} и {@link isDate}).","params":[["minAgeValue","- Минимально допустимый возраст (в полных годах)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `minAge` и `currentAge`."]],"returns":"Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)","example":"Минимальный возраст\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, minAge } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.birthDate, [required(), minAge(18, { message: \'Вам должно быть не менее 18 лет\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","form-types","type-safety-recipes"],"sourcePath":"src/form/validators/min-age.ts","entries":["./validators"],"package":"@reformer/core","usage":3},{"name":"minDate","kind":"function","signature":"export function minDate<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(minDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора минимальной даты (включительно).","description":"Фабрика валидатора минимальной даты (включительно).\\n\\nСравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты\\nпропускаются (используйте {@link required} и {@link isDate}).","params":[["minDateValue","- Минимально допустимая дата (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадает `minDate`."]],"returns":"Чистый валидатор {@link Validator} для поля даты (`string | Date`)","example":"Минимальная дата\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, minDate } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.startDate, [required(), minDate(new Date(), { message: \'Дата не раньше сегодня\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","form-types","type-safety-recipes"],"sourcePath":"src/form/validators/min-date.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"minFiles","kind":"function","signature":"export function minFiles<TForm = unknown, TField = unknown>(\\n min: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора минимального количества файлов.","description":"Фабрика валидатора минимального количества файлов.\\n\\nРаботает с массивом файлов (одиночный файл считается как 1). Пустые значения\\n(`null`/`undefined`/`\'\'`/`[]`) пропускаются — «нужен хотя бы один файл» выражается\\nсвязкой `required()` + `minFiles(n)`, как и у {@link minLength}.","params":[["min","- Минимально допустимое количество файлов (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `minFiles` и `actualCount`."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Не менее двух документов\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, minFiles } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [required(), minFiles(2, { message: \'Приложите минимум 2 документа\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/min-files.ts","entries":["./validators"],"package":"@reformer/core","usage":4},{"name":"minFileSize","kind":"function","signature":"export function minFileSize<TForm = unknown, TField = unknown>(\\n minSize: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора минимального размера файла.","description":"Фабрика валидатора минимального размера файла.\\n\\nРаботает с одиночным файлом или массивом (`File` либо файлоподобный дескриптор с\\n`name`/`size`). Проверяется каждый файл; в ошибку попадает первый нарушивший.\\nТиповой сценарий — отсев пустых (0-байтовых) файлов: `minFileSize(1)`.\\nПустые значения (`null`/`undefined`/`\'\'`/`[]`) и элементы без числового `size`\\nпропускаются (используйте {@link required} для обязательности).","params":[["minSize","- Минимально допустимый размер файла в байтах (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `minFileSize`, `fileName` и `actualSize`."]],"returns":"Чистый валидатор {@link Validator} для файла или массива файлов","example":"Отсев пустых файлов\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { minFileSize } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.documents, [minFileSize(1, { message: \'Файл пустой\' })]);\\n});\\n```","examplesCount":1,"sourcePath":"src/form/validators/min-file-size.ts","entries":["./validators"],"package":"@reformer/core","usage":2},{"name":"minLength","kind":"function","signature":"export function minLength<TForm = unknown, TField = unknown>(\\n minLen: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора минимальной длины строки или массива.","description":"Фабрика валидатора минимальной длины строки или массива.\\n\\nРаботает со строкой или массивом (проверяется `value.length`). Пустые значения\\n(`null`/`undefined`/`\'\'`) и значения без числового `length` пропускаются\\n(используйте {@link required} для обязательности).","params":[["minLen","- Минимально допустимая длина (включительно)"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадают `minLength` и `actualLength`."]],"returns":"Чистый валидатор {@link Validator} для строки или массива","example":"Минимальная длина строки\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, minLength } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.name, [minLength(2)]);\\nvalidate(model.$.password, [required(), minLength(8, { message: \'Минимум 8 символов\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","complete-import","form-types","nonexistent-api","submit-and-reset","type-safety-recipes","validation-strategy"],"sourcePath":"src/form/validators/min-length.ts","entries":["./validators"],"package":"@reformer/core","usage":33},{"name":"ModelApi","kind":"interface","signature":"export interface ModelApi<T> {\\n /**\\n * Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`.\\n * Сам узел — {@link ReadonlySignal} модели целиком: `model.$.subscribe(v => …)`.\\n */\\n readonly $: ModelGroupSignals<T>;\\n /** Снимок значений (без подписки) — для submit. */\\n get(): T;\\n /**\\n * Полная установка значений: принимает объект целиком (все ключи `T`) и записывает их в модель.\\n * Производными полями (цели `compute`) владеет compute — их значения из payload игнорируются.\\n * Не меняет initial-снимок. Для частичного обновления (только переданные ключи) — {@link ModelApi.patch}.\\n */\\n set(value: T): void;\\n /**\\n * Частичное слияние значений (load/patch с сервера): обновляет только переданные ключи,\\n * отсутствующие ключи НЕ трогаются. Не меняет initial-снимок.\\n */\\n patch(value: Partial<T>): void;\\n /** Отличаются ли текущие значения от initial-снимка (value-diff). */\\n isDirty(): boolean;\\n /** Сбросить значения к initial-снимку. */\\n reset(): void;\\n /** Зафиксировать текущие значения как новый initial-снимок («точка отсчёта»). */\\n captureInitial(): void;\\n /** Резолв строкового пути в сигнал (для error-routing/мостов). */\\n signalAt(path: string): PathAwareSignal<unknown> | undefined;\\n}","summary":"API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).","description":"API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).\\n\\n⚠️ Имена методов (`$`/`get`/`set`/`patch`/`isDirty`/`reset`/`signalAt`/`captureInitial`)\\nзарезервированы: одноимённое поле формы их затеняет (редкий краевой случай).","params":[],"examplesCount":0,"topics":["submit-and-reset"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"ModelArray","kind":"interface","signature":"export interface ModelArray<U> {\\n /**\\n * Путь массива в модели (dot-нотация). Предоставляется рантаймом (value-прокси) и требуется\\n * рендер-слою для резолва узла массива (напр. `ArrayRenderNode` в `@reformer/renderer-react`).\\n */\\n readonly __path: string;\\n /** Реактивная длина. */\\n readonly length: number;\\n /** Добавить элемент в конец (значение элемента целиком). */\\n push(item: U): void;\\n /** Вставить элемент по индексу. */\\n insertAt(index: number, item: U): void;\\n /** Удалить элемент по индексу. */\\n removeAt(index: number): void;\\n /** Переместить элемент. */\\n move(from: number, to: number): void;\\n /** Поменять местами два элемента. */\\n swap(a: number, b: number): void;\\n /** Очистить массив. */\\n clear(): void;\\n /** Элемент по индексу: объект → под-модель, массив → {@link ModelArray}, лист → значение. */\\n at(\\n index: number\\n ): NonNullable<U> extends object ? ModelArrayItem<U> : ModelArrayItem<U> | undefined;\\n /** Map по элементам (объект → {@link FormModel}, Opaque/примитив → значение, массив → {@link ModelArray}). */\\n map<R>(fn: (item: ModelArrayItem<U>, index: number) => R): R[];\\n /** Итерация по элементам (см. {@link ModelArrayItem}). */\\n forEach(fn: (item: ModelArrayItem<U>, index: number) => void): void;\\n /** Снимок массива значений (без подписки). */\\n toArray(): U[];\\n /** Индексный value-доступ. */\\n [index: number]: ModelValue<U>;\\n}","summary":"Реактивный массив модели.","description":"Реактивный массив модели. Мутации (`push`/`removeAt`/…) меняют длину реактивно;\\n`map`/`forEach`/`at` отдают под-модель элемента ({@link FormModel}) для объектных элементов.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","complete-import","arrays","array-operations"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core","usage":1},{"name":"ModelArrayControl","kind":"interface","signature":"export interface ModelArrayControl<TItem extends object> {\\n readonly length: number;\\n at(index: number): FormModel<TItem> | undefined;\\n push(item: TItem): void;\\n insertAt(index: number, item: TItem): void;\\n removeAt(index: number): void;\\n move(from: number, to: number): void;\\n swap(a: number, b: number): void;\\n clear(): void;\\n toArray(): TItem[];\\n}","summary":"Минимальный контракт реактивного массива модели, используемый узлом.","description":"Минимальный контракт реактивного массива модели, используемый узлом.","params":[],"examplesCount":0,"sourcePath":"src/form/nodes/model-array-node.ts","entries":["."],"package":"@reformer/core"},{"name":"ModelArrayNode","kind":"class","signature":"export class ModelArrayNode<T extends object> extends FormNode<T[]> { /* … */ }","summary":"Узел массива, делегирующий данные массиву {@link FormModel} (архитектура M1).","description":"Узел массива, делегирующий данные массиву {@link FormModel} (архитектура M1).\\n\\nВ отличие от {@link ArrayNode} (владеет элементами сам), `ModelArrayNode` НЕ владеет данными:\\nмассив принадлежит модели, а узел держит per-item формы элементов (привязанные к сигналам\\nпод-моделей) и синхронизирует их с длиной массива модели. Мутации (`push`/`removeAt`/`move`/…)\\nделегируются массиву модели; per-item формы кэшируются по идентичности под-модели, поэтому при\\nreorder/повторном рендере не пересоздаются (состояние и валидация сохраняются). Реализует тот же\\nконтракт, что ждут секции массива и `useFormControl` (`length`/`value`/`valid`/`errors`/`at`/`push`/…).\\n\\nОбычно создаётся не напрямую, а `createForm({ model, schema })`: когда в схеме встречается узел\\nмассива `{ array: model.<field>, item: (item) => itemSchema }`, форма материализует его как\\n`ModelArrayNode` и кладёт под `form.<field>` (совместим с `FormArraySection`).","params":[],"example":"Массив как часть формы (через createForm)\\n```typescript\\nconst model = createModel<{ rows: { name: string; qty: number }[] }>({ rows: [] });\\n\\nconst rowItem = (item: FormModel<{ name: string; qty: number }>) => ({\\nname: { value: item.$.name, component: InputField },\\nqty: { value: item.$.qty, component: InputField },\\n});\\n\\nconst form = createForm({\\nmodel,\\nschema: {\\nchildren: [{ array: model.rows, item: rowItem }],\\n},\\n});\\n\\nconst rows = form.rows as unknown as ModelArrayNode<{ name: string; qty: number }>;\\nrows.push({ name: \'A\', qty: 1 }); // мутация уезжает в model.rows\\nrows.at(0)?.name.setValue(\'B\'); // правка поля элемента доезжает в под-модель\\nrows.length.value; // 1 (реактивная длина)\\n```","examplesCount":1,"topics":["api-reference","arrays"],"sourcePath":"src/form/nodes/model-array-node.ts","entries":["."],"package":"@reformer/core","usage":1},{"name":"ModelArraySignals","kind":"type","signature":"export type ModelArraySignals<U, V> = ContainerSignal<V, \'length\'> & {\\n readonly length: number;\\n readonly [index: number]: ModelSignalNode<U>;\\n};","summary":"Узел-массив дерева `model.$`: индексируемый доступ к под-сигналам элементов, реактивная `length` и {@link ReadonlySignal} значения массива целиком (реагирует и на правку элемента, и на изменение состава — push/removeAt/move).","description":"Узел-массив дерева `model.$`: индексируемый доступ к под-сигналам элементов, реактивная `length`\\nи {@link ReadonlySignal} значения массива целиком (реагирует и на правку элемента, и на изменение\\nсостава — push/removeAt/move).","params":[],"examplesCount":0,"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core","usage":2},{"name":"ModelGroupSignals","kind":"type","signature":"export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;","summary":"Узел-группа дерева `model.$`: доступ к под-сигналам полей ({@link ModelSignals}) И одновременно {@link ReadonlySignal} агрегированного значения группы — `.value`/`.peek()`/`.subscribe()`.","description":"Узел-группа дерева `model.$`: доступ к под-сигналам полей ({@link ModelSignals}) И одновременно\\n{@link ReadonlySignal} агрегированного значения группы — `.value`/`.peek()`/`.subscribe()`.\\n\\n⚠️ Поле формы с именем `value`/`peek`/`subscribe`/`valueOf`/`toString`/`toJSON`/`brand` затеняет\\nодноимённое свойство сигнала (редкий краевой случай); `subscribe` при этом продолжает работать.","params":[],"examplesCount":0,"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"ModelObject","kind":"type","signature":"export type ModelObject<T> = {\\n [K in keyof T]: ModelValue<T[K]>;\\n};","summary":"Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства (чтение реактивно внутри `effect`/`computed`, запись — присваиванием).","description":"Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства\\n(чтение реактивно внутри `effect`/`computed`, запись — присваиванием). Вложенные объекты-поля\\nрезолвятся в под-модели {@link FormModel} (см. {@link ModelValue}), массивы — в {@link ModelArray}.","params":[],"examplesCount":0,"topics":["api-reference"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"ModelSignals","kind":"type","signature":"export type ModelSignals<T> = {\\n [K in keyof T]: ModelSignalNode<T[K]>;\\n};","summary":"Карта под-сигналов объекта в дереве `model.$` (без свойств самого узла — их добавляет {@link ModelGroupSignals}).","description":"Карта под-сигналов объекта в дереве `model.$` (без свойств самого узла — их добавляет\\n{@link ModelGroupSignals}).","params":[],"examplesCount":0,"topics":["api-reference","complete-import","type-safety-recipes"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"ModelValue","kind":"type","signature":"export type ModelValue<V> =\\n NonNullable<V> extends ReadonlyArray<infer U>\\n ? ModelArray<U>\\n : NonNullable<V> extends Opaque\\n ? V\\n : NonNullable<V> extends object\\n ? FormModel<NonNullable<V>>\\n : V;","summary":"Значение поля в value-доступе модели: - массив → {@link ModelArray} - спец-объект (Date/File/Blob) → как есть - объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…); промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>` - примитив → значение","description":"Значение поля в value-доступе модели:\\n- массив → {@link ModelArray}\\n- спец-объект (Date/File/Blob) → как есть\\n- объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…);\\n промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>`\\n- примитив → значение","params":[],"examplesCount":0,"topics":["api-reference"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"multipleOf","kind":"function","signature":"export function multipleOf<TForm = unknown, TField extends number | null | undefined = number>(\\n divisor: number,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что число кратно заданному.","description":"Фабрика валидатора, проверяющего что число кратно заданному.\\n\\nПустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).","params":[["divisor","- Делитель: значение должно быть кратно ему"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадает `multipleOf` (делитель)."]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Проверка кратности\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { multipleOf } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.rating, [multipleOf(0.5, { message: \'Только шаг 0.5\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/multiple-of.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"NodeFactory","kind":"class","signature":"export class NodeFactory {\\n /**\\n * Создает узел формы на основе конфигурации\\n *\\n * ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую\\n *\\n * Автоматически определяет тип узла:\\n * - FieldNode: имеет value и component\\n * - ArrayNode: массив [schema, ...items] или { schema, initialItems }\\n * - GroupNode: объект без value, component, schema\\n *\\n * @param config Конфигурация узла\\n * @returns Экземпляр FieldNode, GroupNode или ArrayNode\\n * @throws Error если конфиг не соответствует ни одному типу\\n *\\n * @example\\n * ```typescript\\n * const factory = new NodeFactory();\\n *\\n * Конфиг node-level (не layout-схема M1, где `validators` уже нет).\\n * // FieldNode\\n * const field = factory.createNode({\\n * value: \'test@mail.com\',\\n * component: InputField,\\n * validators: [required, email]\\n * });\\n *\\n * // GroupNode\\n * const group = factory.createNode({\\n * email: { value: \'\', component: InputField },\\n * password: { value: \'\', component: InputField }\\n * });\\n *\\n * // ArrayNode (объект)\\n * const array = factory.createNode({\\n * schema: { title: { value: \'\', component: InputField } },\\n * initialItems: [{ title: \'Item 1\' }]\\n * });\\n *\\n * // ArrayNode (массив) - новый формат\\n * const array2 = factory.createNode([\\n * { title: { value: \'\', component: InputField } }, // schema\\n * { title: \'Item 1\' }, // initial item 1\\n * { title: \'Item 2\' } // initial item 2\\n * ]);\\n * ```\\n */ /* … */ }","summary":"Фабрика для создания узлов формы.","description":"Фабрика для создания узлов формы.\\n\\nОпределяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).\\nИспользуется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.","params":[],"example":"```typescript\\nimport { NodeFactory } from \'@reformer/core\';\\n\\nconst factory = new NodeFactory();\\nconst node = factory.createNode({ value: \'\', component: InputField }); // → FieldNode<string>\\n```","examplesCount":1,"sourcePath":"src/form/factories/node-factory.ts","entries":["."],"package":"@reformer/core"},{"name":"nonNegative","kind":"function","signature":"export function nonNegative<TForm = unknown, TField extends number | null | undefined = number>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).","description":"Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).\\n\\nПустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Проверка неотрицательности\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { nonNegative } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.balance, [nonNegative({ message: \'Баланс не может быть отрицательным\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/non-negative.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"nonZero","kind":"function","signature":"export function nonZero<TForm = unknown, TField extends number | null | undefined = number>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что число не равно нулю.","description":"Фабрика валидатора, проверяющего что число не равно нулю.\\n\\nПустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для числового поля","example":"Проверка «не ноль»\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { nonZero } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.divisor, [nonZero({ message: \'Не может быть нулём\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/non-zero.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"onChange","kind":"function","signature":"export function onChange<T>(\\n source: ReadonlySignal<T>,\\n cb: (value: T, ctx: ChangeContext) => void,\\n options?: { immediate?: boolean; debounce?: number }\\n): void","summary":"Реакция на изменение поля; `{ debounce, immediate }`.","description":"Реакция на изменение поля; `{ debounce, immediate }`.\\n\\nКолбэк выполняется ВНЕ effect-контекста (микротаск/таймер) — можно безопасно писать сигналы и ноды\\n(`updateComponentProps`/`reset`/`clear`) без ручного `defer` и без «Cycle detected».\\n\\nДля async-колбэков 2-м аргументом приходит `{ signal }` (AbortSignal): при следующей смене значения\\nпредыдущий `signal` аннулируется. Передавай его в `fetch` (сетевая отмена) или проверяй\\n`signal.aborted` перед применением результата — это убирает гонки устаревших ответов (F2).","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","arrays","async-watchfield","array-cleanup","extended-mistakes","project-structure","ui-components","nonexistent-api","reading-values","compute-vs-watch","cycle-detection","sync-fields","async-preload","type-safety-recipes","async-validator-debounce","async-options-loading"],"sourcePath":"src/form/behaviors/operators.ts","entries":["./behaviors"],"package":"@reformer/core","usage":22},{"name":"onDispose","kind":"function","signature":"export function onDispose(cleanup: BehaviorCleanup): void","summary":"Зарегистрировать произвольную отписку в активной схеме.","description":"Зарегистрировать произвольную отписку в активной схеме.","params":[],"examplesCount":0,"topics":["api-reference"],"sourcePath":"src/form/behaviors/context.ts","entries":["./behaviors"],"package":"@reformer/core"},{"name":"pastDate","kind":"function","signature":"export function pastDate<\\n TForm = unknown,\\n TField extends string | Date | null | undefined = string | Date,\\n>(options?: ValidateOptions): Validator<TForm, TField>","summary":"Фабрика валидатора, проверяющего что дата не в будущем.","description":"Фабрика валидатора, проверяющего что дата не в будущем.\\n\\nДата не должна быть позже сегодняшнего дня (сравнение по нормализованным датам).\\nПустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для поля даты (`string | Date`)","example":"Дата не в будущем\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, pastDate } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.birthDate, [required(), pastDate({ message: \'Дата рождения не может быть в будущем\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures"],"sourcePath":"src/form/validators/past-date.ts","entries":["./validators"],"package":"@reformer/core","usage":5},{"name":"PathAwareSignal","kind":"type","signature":"export type PathAwareSignal<T> = Signal<T> & {\\n /** Путь поля в модели (dot-нотация). На элементах массива включает индекс. */\\n readonly __path: string;\\n};","summary":"Сигнал, который знает свой путь в модели (`\'personalData.lastName\'`).","description":"Сигнал, который знает свой путь в модели (`\'personalData.lastName\'`).\\nИспользуется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","complete-import","formschema","nonexistent-api","reading-values"],"sourcePath":"src/model/types.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"pattern","kind":"function","signature":"export function pattern<TForm = unknown, TField extends string | null | undefined = string>(\\n regex: RegExp,\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора регулярного выражения.","description":"Фабрика валидатора регулярного выражения.\\n\\nПустые значения (`\'\'`/`null`/`undefined`) пропускаются (используйте {@link required}\\nдля обязательности).","params":[["regex","- Регулярное выражение для проверки значения"],["options","- Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически\\nпопадает `pattern` (строка-источник regex)."]],"returns":"Чистый валидатор {@link Validator} для строкового поля","example":"Проверка по регулярному выражению\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, pattern } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.name, [pattern(/^[a-zA-Zа-яА-Я]+$/, { message: \'Только буквы\' })]);\\nvalidate(model.$.phone, [required(), pattern(/^\\\\+7 \\\\(\\\\d{3}\\\\) \\\\d{3}-\\\\d{2}-\\\\d{2}$/, { message: \'Формат +7 (999) 123-45-67\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","complete-import","nonexistent-api","copy-from","async-validator-debounce"],"sourcePath":"src/form/validators/pattern.ts","entries":["./validators"],"package":"@reformer/core","usage":21},{"name":"phone","kind":"function","signature":"export function phone<TForm = unknown, TField extends string | null | undefined = string>(\\n options?: PhoneValidatorOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора номера телефона.","description":"Фабрика валидатора номера телефона.\\n\\nПроверяет значение по regex выбранного {@link PhoneFormat}. Пустые значения\\n(`\'\'`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).","params":[["options","- Опции валидатора {@link PhoneValidatorOptions}. В `params` ошибки\\nавтоматически попадает выбранный `format`."]],"returns":"Чистый валидатор {@link Validator} для строкового поля","example":"Проверка номера телефона\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, phone } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.phone, [required(), phone({ format: \'ru\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","complete-import","form-types","ui-components","transform-value"],"sourcePath":"src/form/validators/phone.ts","entries":["./validators"],"package":"@reformer/core","usage":20},{"name":"PhoneFormat","kind":"type","signature":"export type PhoneFormat = \'international\' | \'ru\' | \'us\' | \'any\';","summary":"Формат проверки номера телефона для валидатора {@link phone}.","description":"Формат проверки номера телефона для валидатора {@link phone}.\\n\\n- `international` — международный формат E.164 (`+?[1-9]\\\\d{1,14}`);\\n- `ru` — российские номера (`+7`/`7`/`8`, коды `4`/`8`/`9`, с разделителями);\\n- `us` — североамериканские номера (NANP);\\n- `any` — свободный формат: цифры, скобки и разделители (по умолчанию).","params":[],"examplesCount":0,"topics":["api-signatures"],"sourcePath":"src/form/validators/phone.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"PhoneValidatorOptions","kind":"interface","signature":"export interface PhoneValidatorOptions extends ValidateOptions {\\n /** Формат проверки {@link PhoneFormat}. По умолчанию `\'any\'`. */\\n format?: PhoneFormat;\\n}","summary":"Опции валидатора {@link phone}.","description":"Опции валидатора {@link phone}. Расширяют {@link ValidateOptions} (`message`, `params`)\\nвыбором формата номера.","params":[],"examplesCount":0,"sourcePath":"src/form/validators/phone.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"registerSignalNode","kind":"function","signature":"export function registerSignalNode(signal: Signal<any>, node: FormNode<any>): void","summary":"Связать сигнал модели с его нодой формы.","description":"Связать сигнал модели с его нодой формы.\\n\\nВызывается движком при сборке формы (`createForm`/{@link createFormFromModel}) для каждого\\nлистового поля. Прикладной код обычно этот реестр не заполняет напрямую.","params":[["signal","- Сигнал значения из {@link FormModel} (ручка поля, `model.$.path`)"],["node","- Нода формы, отвечающая за это поле"]],"example":"Привязка листовых полей при построении формы\\n```typescript\\nimport { registerSignalNode } from \'@reformer/core\';\\n\\nconst sig = model.signalAt(\'profile.email\');\\nconst node = group.getFieldByPath(\'profile.email\');\\nif (sig && node) registerSignalNode(sig, node);\\n```","examplesCount":1,"related":["getNodeForSignal"],"sourcePath":"src/form/signal-node-registry.ts","entries":["."],"package":"@reformer/core"},{"name":"required","kind":"function","signature":"export function required<TForm = unknown, TField = unknown>(\\n options?: ValidateOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора обязательного поля.","description":"Фабрика валидатора обязательного поля.\\n\\nВозвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.\\n\\nПустыми считаются: `null`, `undefined`, `\'\'` (пустая строка), `[]` (пустой массив —\\nобязательный multi-select / FormArray без выбранных элементов).\\nДля boolean полей требуется значение `true`.","params":[["options","- Опции валидатора ({@link ValidateOptions}): `message`, `params`"]],"returns":"Чистый валидатор {@link Validator} для поля схемы","example":"Обязательные поля в схеме формы\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.email, [required()]);\\nvalidate(model.$.phone, [required({ message: \'Укажите номер телефона\' })]);\\nvalidate(model.$.agreeToTerms, [required({ message: \'Необходимо принять условия\' })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","formschema","arrays","multi-step","extended-mistakes","nonexistent-api","conditional-fields","reset-when","submit-and-reset","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/validators/required.ts","entries":["./validators"],"package":"@reformer/core","usage":126},{"name":"resetWhen","kind":"function","signature":"export function resetWhen<T>(\\n target: Signal<T>,\\n condition: () => boolean,\\n options?: { resetValue?: T }\\n): BehaviorCleanup","summary":"Сброс значения поля к `resetValue` (по умолчанию `null`), когда `condition` истинно.","description":"Сброс значения поля к `resetValue` (по умолчанию `null`), когда `condition` истинно.","params":[],"example":"```typescript\\nresetWhen(model.$.cardNumber, () => model.paymentType !== \'card\', { resetValue: \'\' });\\n```","examplesCount":1,"topics":["api-reference","api-signatures","complete-import","conditional-fields","cycle-detection","copy-from","reset-when"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":4},{"name":"revalidateWhen","kind":"function","signature":"export function revalidateWhen(\\n deps: ReadonlySignal<unknown>[],\\n revalidate: () => void\\n): BehaviorCleanup","summary":"Вызывает `revalidate()` при изменении зависимостей (не на инициализации).","description":"Вызывает `revalidate()` при изменении зависимостей (не на инициализации). Валидация on-demand\\n(`validateModel` из `@reformer/core/validation`), поэтому ревалидация выражается явным колбэком.","params":[],"example":"```typescript\\nrevalidateWhen([model.$.maxAmount], () => void validateModel(model, schema));\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","complete-import","extended-mistakes","nonexistent-api","revalidate-when","submit-and-reset","async-validator-debounce","validation-strategy"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":5},{"name":"Rule","kind":"type","signature":"export type Rule<TField> = (value: TField, scope: never, root: never) => ValidationError | null;","summary":"Синхронное правило поля типа `TField`.","description":"Синхронное правило поля типа `TField`. Проверяется ТОЛЬКО значение (`value`).\\n\\nПозиционные `scope`/`root` помечены `never` намеренно: так встроенные value-only фабрики\\n(`required()`/`min()`/… — они `(value, model, root) => …`) и inline-правила `(value) => …`\\nОБА присваиваются в `Rule<TField>[]` без `any`, при этом сохраняется проверка типа поля\\n(`validate(model.$.age, [email()])` подсветится — `email` ждёт `string`, поле `number`).\\nНа вызове раннер приводит правило к callable и передаёт `(value, model, model)`.","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","project-structure","nonexistent-api","compute-vs-watch","type-safety-recipes"],"sourcePath":"src/form/validation/types.ts","entries":["./validation"],"package":"@reformer/core","usage":82},{"name":"runOutsideEffect","kind":"function","signature":"export function runOutsideEffect(fn: () => void | Promise<void>): () => void","summary":"Выполняет функцию вне контекста effect (отложенная запись на микротаск).","description":"Выполняет функцию вне контекста effect (отложенная запись на микротаск).\\n\\nСбои fn (синхронный throw и async-rejection) маршрутизируются dev-логгером (logDeferError), а не\\nвсплывают неперехваченными. Возвращает отменитель: вызов до срабатывания микротаска отменяет запись\\n(liveness-охрана — не писать против снесённого узла при dispose в том же тике).","params":[["fn","- Функция для выполнения"]],"returns":"Отменитель ещё не выполненной записи (no-op, если запись уже выполнена)","example":"```typescript\\neffect(() => {\\n const value = signal.value;\\n const cancel = runOutsideEffect(() => {\\n otherSignal.value = transform(value);\\n });\\n onDispose(cancel); // отменить ожидающую запись, если узел снесут в этом же тике\\n});\\n```","examplesCount":1,"topics":["cycle-detection","copy-from","sync-fields","transform-value"],"sourcePath":"src/model/safe-effect.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"safeCallback","kind":"function","signature":"export function safeCallback<TArgs extends unknown[]>(\\n callback: (...args: TArgs) => void | Promise<void>\\n): (...args: TArgs) => void","summary":"Создает callback, который выполняется вне контекста effect Откладывает вызов через {@link runOutsideEffect} — то есть получает маршрутизацию ошибок и обработку async-rejection «бесплатно».","description":"Создает callback, который выполняется вне контекста effect\\n\\nОткладывает вызов через {@link runOutsideEffect} — то есть получает маршрутизацию ошибок и\\nобработку async-rejection «бесплатно».","params":[["callback","- Функция для выполнения"]],"returns":"Обёрнутая функция, безопасная для вызова внутри effect","example":"```typescript\\n// Вместо:\\neffect(() => {\\n queueMicrotask(() => {\\n callback(value, context);\\n });\\n});\\n\\n// Используем:\\neffect(() => {\\n safeCallback(callback)(value, context);\\n});\\n```","examplesCount":1,"sourcePath":"src/model/safe-effect.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"safeDebouncedCallback","kind":"function","signature":"export function safeDebouncedCallback(\\n callback: () => void | Promise<void>,\\n withDebounce: (fn: () => void) => void\\n): () => void","summary":"Создает версию callback с поддержкой debounce, безопасную для effect `withDebounce` уже откладывает вызов (таймер) — этого достаточно для выхода из effect-контекста, поэтому дополнительного `queueMicrotask` нет (устранён двойной defer).","description":"Создает версию callback с поддержкой debounce, безопасную для effect\\n\\n`withDebounce` уже откладывает вызов (таймер) — этого достаточно для выхода из effect-контекста,\\nпоэтому дополнительного `queueMicrotask` нет (устранён двойной defer). Сбои callback (в т.ч.\\nasync-rejection) маршрутизируются dev-логгером (logDeferError).","params":[["callback","- Функция для выполнения"],["withDebounce","- Функция debounce обёртки из BehaviorRegistry"]],"returns":"Обёрнутая функция","example":"```typescript\\nreturn effect(() => {\\n const value = node.value.value;\\n safeDebouncedCallback(\\n () => callback(value, context),\\n withDebounce\\n )();\\n});\\n```","examplesCount":1,"sourcePath":"src/model/safe-effect.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"SchemaArrayControl","kind":"interface","signature":"export interface SchemaArrayControl {\\n /** Путь массива в модели (dot-нотация) — нужен для резолва узла массива. */\\n readonly __path: string;\\n /** Реактивная длина. */\\n readonly length: number;\\n at(index: number): unknown;\\n push(item: unknown): void;\\n removeAt(index: number): void;\\n}","summary":"Минимальный контракт реактивного массива модели ({@link FormSchemaNode.array}).","description":"Минимальный контракт реактивного массива модели ({@link FormSchemaNode.array}).\\nСовпадает по форме с рантайм-фасадом `model.<array>` (см. `ModelArray`); рендерерский\\n`RenderModelArrayControl` — его расширение (добавляет `move`).","params":[],"examplesCount":0,"sourcePath":"src/form/types/schema-node.ts","entries":["."],"package":"@reformer/core"},{"name":"SetValueOptions","kind":"interface","signature":"export interface SetValueOptions {\\n /** Не вызывать событие изменения (не триггерить валидацию) */\\n emitEvent?: boolean;\\n // onlySelf удалён в 7.0: опция объявлялась, но не была реализована ни одной из четырёх\\n // реализаций setValue — передача значения ни на что не влияла.\\n}","summary":"Опции для setValue","description":"Опции для setValue","params":[],"examplesCount":0,"sourcePath":"src/form/nodes/form-node.ts","entries":["."],"package":"@reformer/core"},{"name":"SubmitOptions","kind":"interface","signature":"export interface SubmitOptions {\\n /** Пропустить валидацию перед submit */\\n skipValidation?: boolean;\\n /** Пропустить markAsTouched перед submit */\\n skipTouch?: boolean;\\n}","summary":"Опции для submit","description":"Опции для submit","params":[],"examplesCount":0,"sourcePath":"src/form/form-submitter.ts","entries":["."],"package":"@reformer/core"},{"name":"SubmitResult","kind":"interface","signature":"export interface SubmitResult<R> {\\n /** Успешно ли выполнен submit */\\n success: boolean;\\n /** Результат от onSubmit callback */\\n data: R | null;\\n /** Ошибка, если submit не удался */\\n error?: Error;\\n}","summary":"Результат submit","description":"Результат submit","params":[],"examplesCount":0,"sourcePath":"src/form/form-submitter.ts","entries":["."],"package":"@reformer/core"},{"name":"SubmittableForm","kind":"interface","signature":"export interface SubmittableForm<T extends object> {\\n /** Пометить все поля как touched */\\n markAsTouched(): void;\\n /** Валидировать форму */\\n validate(): Promise<boolean>;\\n /** Получить значения формы */\\n getValue(): T;\\n}","summary":"Интерфейс формы для FormSubmitter Минимальный контракт для работы с любой формой","description":"Интерфейс формы для FormSubmitter\\nМинимальный контракт для работы с любой формой","params":[],"examplesCount":0,"sourcePath":"src/form/form-submitter.ts","entries":["."],"package":"@reformer/core"},{"name":"SubscriptionManager","kind":"class","signature":"export class SubscriptionManager {\\n /**\\n * Хранилище подписок\\n * Ключ: уникальный идентификатор подписки\\n * Значение: функция отписки (dispose)\\n */ /* … */ }","summary":"Менеджер подписок для FormNode Централизует управление effect-подписками в узлах формы, предотвращает утечки памяти и упрощает отладку.","description":"Менеджер подписок для FormNode\\n\\nЦентрализует управление effect-подписками в узлах формы,\\nпредотвращает утечки памяти и упрощает отладку.\\n\\nКаждая подписка имеет уникальный ключ, что позволяет:\\n- Отписываться от конкретной подписки по ключу\\n- Автоматически заменять существующие подписки\\n- Отслеживать количество активных подписок (для отладки)","params":[],"example":"```typescript\\nclass FieldNode {\\n private subscriptions = new SubscriptionManager();\\n\\n watch(callback: Function) {\\n const dispose = effect(() => callback(this.value.value));\\n return this.subscriptions.add(\'watch\', dispose);\\n }\\n\\n dispose() {\\n this.subscriptions.clear();\\n }\\n}\\n```","examplesCount":1,"sourcePath":"src/form/nodes/subscription-manager.ts","entries":["."],"package":"@reformer/core"},{"name":"syncFields","kind":"function","signature":"export function syncFields<T>(\\n a: Signal<T>,\\n b: Signal<T>,\\n options?: { transform?: (value: T) => T }\\n): BehaviorCleanup","summary":"Двусторонняя синхронизация двух полей (опционально с трансформом `a → b`).","description":"Двусторонняя синхронизация двух полей (опционально с трансформом `a → b`).\\nСходимость обеспечивается peek-guard\'ом; флаг предотвращает лишние круги.","params":[],"example":"```typescript\\nsyncFields(model.$.field1, model.$.field2);\\n```","examplesCount":1,"topics":["api-reference","api-signatures","complete-import","cycle-detection","copy-from","sync-fields","transform-value"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":4},{"name":"toFileArray","kind":"function","signature":"export function toFileArray(value: unknown): FileLike[] | null","summary":"Нормализует значение file-поля в массив файлоподобных элементов.","description":"Нормализует значение file-поля в массив файлоподобных элементов.\\n\\nОдиночный {@link FileLike} оборачивается в массив; из массива отбираются только\\nфайлоподобные элементы. Для прочих значений — `null` (валидатор пропускает).","params":[["value","- Значение поля (`FileLike`, `FileLike[]` или что-то ещё)"]],"returns":"Массив файлоподобных элементов или `null`","examplesCount":0,"sourcePath":"src/form/validators/file-utils.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"transformValue","kind":"function","signature":"export function transformValue<T>(\\n target: Signal<T>,\\n transformer: (value: T) => T\\n): BehaviorCleanup","summary":"Трансформация значения поля (идемпотентная): при изменении пишет `transformer(value)` обратно.","description":"Трансформация значения поля (идемпотентная): при изменении пишет `transformer(value)` обратно.\\nЗапись отложена (`runOutsideEffect`) во избежание «Cycle detected» (эффект читает и пишет один сигнал).","params":[],"example":"```typescript\\ntransformValue(model.$.promoCode, (v) => (v ?? \'\').toUpperCase());\\n```","examplesCount":1,"topics":["api-reference","api-signatures","complete-import","extended-mistakes","nonexistent-api","cycle-detection","sync-fields","transform-value"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model","./behaviors"],"package":"@reformer/core","usage":6},{"name":"UnknownRecord","kind":"type","signature":"export type UnknownRecord = Record<string, unknown>;","summary":"Тип для Record с unknown значениями Используется вместо инлайнового `Record<string, unknown>`","description":"Тип для Record с unknown значениями\\nИспользуется вместо инлайнового `Record<string, unknown>`","params":[],"examplesCount":0,"sourcePath":"src/form/types/index.ts","entries":["."],"package":"@reformer/core"},{"name":"unmarkDerived","kind":"function","signature":"export function unmarkDerived(signal: Signal<any>): void","summary":"Снять пометку производного сигнала (обратная операция к {@link markDerived}).","description":"Снять пометку производного сигнала (обратная операция к {@link markDerived}).\\n\\nВызывается из очистки (`onDispose`) оператора `compute`/`computeFrom`, когда поведение снимается,\\nно модель/сигнал продолжают жить (динамическая перекоммутация: удалить под-схему → сохранить модель\\n→ bulk-set). Без этого сигнал остаётся помеченным навсегда, и bulk-сеттеры навсегда пропускают\\nполе, которое больше ничем не вычисляется.\\n\\nУчитывает счётчик ссылок: пометка снимается только когда снят последний владелец. Вызов на\\nнепомеченном сигнале — безопасный no-op.","params":[["signal","- Сигнал значения из {@link FormModel}, ранее помеченный {@link markDerived}"]],"example":"```typescript\\nimport { markDerived, unmarkDerived } from \'@reformer/core\';\\n\\nmarkDerived(model.$.total);\\nonDispose(() => unmarkDerived(model.$.total)); // при снятии compute снова разрешаем bulk-set\\n```","examplesCount":1,"related":["markDerived"],"sourcePath":"src/model/derived-registry.ts","entries":[".","./model"],"package":"@reformer/core"},{"name":"url","kind":"function","signature":"export function url<TForm = unknown, TField extends string | null | undefined = string>(\\n options?: UrlValidatorOptions\\n): Validator<TForm, TField>","summary":"Фабрика валидатора URL.","description":"Фабрика валидатора URL.\\n\\nПустые значения (`\'\'`/`null`/`undefined`) пропускаются (используйте {@link required}\\nдля обязательности). При `requireProtocol` протокол обязателен; `allowedProtocols`\\nдополнительно ограничивает набор допустимых протоколов.","params":[["options","- Опции валидатора {@link UrlValidatorOptions}"]],"returns":"Чистый валидатор {@link Validator} для строкового поля","example":"Проверка URL\\n```typescript\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, url } from \'@reformer/core/validators\';\\n\\n// Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.\\nconst validation = defineValidationSchema<MyForm>(({ model }) => {\\nvalidate(model.$.website, [required(), url({ message: \'Введите корректный URL\' })]);\\n// Требовать протокол и ограничить схему только https:\\nvalidate(model.$.homepage, [url({ requireProtocol: true, allowedProtocols: [\'https\'] })]);\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","async-validator-debounce"],"sourcePath":"src/form/validators/url.ts","entries":["./validators"],"package":"@reformer/core","usage":3},{"name":"UrlValidatorOptions","kind":"interface","signature":"export interface UrlValidatorOptions extends ValidateOptions {\\n /** Требовать наличие протокола (`http://` или `https://`). По умолчанию `false`. */\\n requireProtocol?: boolean;\\n /**\\n * Список разрешённых протоколов (без `://`), например `[\'https\']`. Если задан,\\n * значение с иным протоколом даёт ошибку с кодом `url_protocol`.\\n */\\n allowedProtocols?: string[];\\n}","summary":"Опции валидатора {@link url}.","description":"Опции валидатора {@link url}. Расширяют {@link ValidateOptions} (`message`, `params`)\\nнастройками проверки протокола.","params":[],"examplesCount":0,"sourcePath":"src/form/validators/url.ts","entries":["./validators"],"package":"@reformer/core"},{"name":"useArrayLength","kind":"function","signature":"export function useArrayLength<T extends object>(control: ArrayNode<T>): number","summary":"React-хук для подписки только на длину массива.","description":"React-хук для подписки только на длину массива.\\n\\nОптимизированная версия {@link useFormControl} для ArrayNode, которая\\nподписывается только на сигнал `length`. Компонент не будет ре-рендериться\\nпри изменении значений вложенных полей.","params":[["control","- ArrayNode для подписки"]],"returns":"Текущая длина массива","example":"```tsx\\nfunction ArrayRenderer({ arrayNode }) {\\n const length = useArrayLength(arrayNode);\\n\\n return (\\n <div>\\n {arrayNode.map((item, index) => (\\n <ItemRenderer key={item.id} item={item} />\\n ))}\\n </div>\\n );\\n}\\n```","examplesCount":1,"topics":["api-reference","complete-import","arrays","reading-values","array-operations"],"sourcePath":"src/platforms/react/hooks/useArrayLength.ts","entries":["."],"package":"@reformer/core"},{"name":"useFormBundle","kind":"function","signature":"export function useFormBundle<B extends FormBundleLike>(factory: () => B): B","summary":"Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте (не при SSR — там эффекты не выполняются).","description":"Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте\\n(не при SSR — там эффекты не выполняются).","params":[["factory","- Фабрика бандла, обычно `() => createCoreForm({…})`."]],"returns":"Стабильный бандл.","example":"```tsx\\nconst credit = useFormBundle(() => createCoreForm<CreditForm>({ model: createCreditModel() }));\\n```","examplesCount":1,"topics":["quick-start","project-structure"],"sourcePath":"src/platforms/react/hooks/use-form-bundle.ts","entries":["."],"package":"@reformer/core","usage":16},{"name":"useFormControl","kind":"function","signature":"export function useFormControl(\\n control: FieldNode<FormValue> | ArrayNode<object> | undefined\\n): FieldControlState<FormValue> | ArrayControlState<object>","summary":"React-хук для подписки на состояние формы (FieldNode или ArrayNode).","description":"React-хук для подписки на состояние формы (FieldNode или ArrayNode).\\n\\nОбеспечивает реактивную связь между состоянием формы и React-компонентами.\\nИспользует `useSyncExternalStore` для оптимальной интеграции с React 18+\\nи Concurrent Mode.\\n\\n## Основные возможности\\n\\n- **Автоматическая подписка** на все сигналы контрола\\n- **Оптимизация ре-рендеров** - компонент обновляется только при реальных изменениях\\n- **Поддержка SSR** через `useSyncExternalStore`\\n- **Типобезопасность** - возвращаемый тип зависит от типа контрола\\n\\n## Когда использовать\\n\\nИспользуйте `useFormControl` когда компоненту нужен доступ к нескольким\\nсвойствам состояния (value, errors, touched и т.д.).\\n\\nДля подписки только на значение используйте {@link useFormControlValue} -\\nэто предотвратит лишние ре-рендеры при изменении других свойств.","params":[["control","- FieldNode, ArrayNode или undefined"]],"returns":"Объект состояния {@link FieldControlState} или {@link ArrayControlState}","example":"Текстовое поле с валидацией\\n```tsx\\nimport { useFormControl } from \'@reformer/core\';\\nimport type { FieldNode } from \'@reformer/core\';\\n\\ninterface TextFieldProps {\\ncontrol: FieldNode<string>;\\nlabel: string;\\n}\\n\\nfunction TextField({ control, label }: TextFieldProps) {\\nconst {\\nvalue,\\ndisabled,\\nshouldShowError,\\nerrors,\\npending\\n} = useFormControl(control);\\n\\nreturn (\\n<div className=\\"field\\">\\n<label>{label}</label>\\n\\n<div className=\\"input-wrapper\\">\\n<input\\n type=\\"text\\"\\n value={value}\\n disabled={disabled}\\n onChange={e => control.setValue(e.target.value)}\\n onBlur={() => control.markAsTouched()}\\n aria-invalid={shouldShowError}\\n/>\\n{pending && <Spinner />}\\n</div>\\n\\n{shouldShowError && errors[0] && (\\n<span className=\\"error\\" role=\\"alert\\">\\n {errors[0].message}\\n</span>\\n)}\\n</div>\\n);\\n}\\n```","examplesCount":5,"related":["useFormControlValue","FieldControlState","ArrayControlState"],"topics":["api-reference","quick-start","common-patterns","common-mistakes","complete-import","ui-components","nonexistent-api","reading-values","async-preload","type-safety-recipes","validation-strategy"],"sourcePath":"src/platforms/react/hooks/useFormControl.ts","entries":["."],"package":"@reformer/core","usage":8},{"name":"useFormControlValue","kind":"function","signature":"export function useFormControlValue<T extends FormValue>(control: FieldNode<T>): T","summary":"React-хук для подписки только на значение поля.","description":"React-хук для подписки только на значение поля.\\n\\nОптимизированная версия {@link useFormControl}, которая подписывается\\nтолько на сигнал `value`. Компонент не будет ре-рендериться при изменении\\n`errors`, `touched`, `valid` и других свойств состояния.\\n\\n## Когда использовать\\n\\n- **Условный рендеринг** на основе значения другого поля\\n- **Вычисляемые значения** зависящие от значения поля\\n- **Read-only отображение** значения без интерактивности\\n- **Оптимизация производительности** когда не нужны другие свойства состояния\\n\\n## Когда НЕ использовать\\n\\nЕсли компоненту нужны `errors`, `touched`, `disabled` или другие свойства -\\nиспользуйте {@link useFormControl}. Множественные подписки на один контрол\\nчерез разные хуки менее эффективны, чем одна подписка через `useFormControl`.","params":[["control","- FieldNode для подписки на значение"]],"returns":"Текущее значение поля","example":"Условный рендеринг секции\\n```tsx\\nimport { useFormControlValue } from \'@reformer/core\';\\n\\ninterface FormFields {\\nhasShipping: FieldNode<boolean>;\\nshippingAddress: GroupNode<AddressFields>;\\n}\\n\\nfunction ShippingSection({ form }: { form: FormFields }) {\\n// Подписка только на значение checkbox\\nconst hasShipping = useFormControlValue(form.hasShipping);\\n\\nif (!hasShipping) {\\nreturn null;\\n}\\n\\nreturn (\\n<div className=\\"shipping-section\\">\\n<h3>Shipping Address</h3>\\n<AddressForm control={form.shippingAddress} />\\n</div>\\n);\\n}\\n```","examplesCount":5,"related":["useFormControl","FieldNode"],"topics":["api-reference","common-patterns","common-mistakes","troubleshooting","complete-import","nonexistent-api","conditional-fields","reading-values"],"sourcePath":"src/platforms/react/hooks/useFormControlValue.ts","entries":["."],"package":"@reformer/core","usage":29},{"name":"useFormValidation","kind":"function","signature":"export function useFormValidation<T>(args: UseFormValidationArgs<T>): UseFormValidationResult","summary":"Декларативный выбор стратегии валидации формы: одна точка вместо ручной разводки `validateModel`/`revalidateWhen`.","description":"Декларативный выбор стратегии валидации формы: одна точка вместо ручной разводки\\n`validateModel`/`revalidateWhen`. Собирает стабильный {@link createFormValidation}-контроллер,\\nармит реактивную стратегию на клиенте (`useEffect` → SSR-safe) и отдаёт `submit`/`isValidating`.\\n\\nСхема-валидации — **стабильная ссылка** (обязанность вызывающего): контроллер мемоизируется по\\n`[model, schema, strategy, debounce, liveAfterSubmit]`.","params":[],"example":"```tsx\\nconst validation = defineValidationSchema<Form>(({ model }) => { ... }); // module-level\\n\\nfunction MyForm() {\\n const { submit, isValidating } = useFormValidation({\\n model, schema: validation, strategy: \'afterFirstSubmit\', debounce: 300,\\n });\\n const onSubmit = async (e: React.FormEvent) => {\\n e.preventDefault();\\n if (await submit()) await api.save(model.get());\\n };\\n return <form onSubmit={onSubmit}>{ ... }<button disabled={isValidating}>Отправить</button></form>;\\n}\\n```","examplesCount":1,"topics":["validation-strategy"],"sourcePath":"src/platforms/react/hooks/use-form-validation.ts","entries":["."],"package":"@reformer/core","usage":4},{"name":"UseFormValidationArgs","kind":"interface","signature":"export interface UseFormValidationArgs<T> {\\n /** Модель данных формы. */\\n model: FormModel<T>;\\n /** Схема валидации. **Стабильная ссылка** (module-level `const` / `useMemo`) — иначе ломается дедуп раннера. */\\n schema: ValidationSchema<T>;\\n /** Стратегия запуска. Default `\'submit\'`. */\\n strategy?: ValidationStrategyKind;\\n /** Debounce (мс) для live-фаз (`change` / live-часть `afterFirstSubmit`). */\\n debounce?: number;\\n /** Режим live-фазы для `afterFirstSubmit`. Default `\'change\'`. */\\n liveAfterSubmit?: \'change\' | \'blur\';\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/platforms/react/hooks/use-form-validation.ts","entries":["."],"package":"@reformer/core"},{"name":"UseFormValidationResult","kind":"interface","signature":"export interface UseFormValidationResult {\\n /** Полный прогон + раскрытие ошибок (`touch:true`); для `onSubmit`. Стабильная ссылка. */\\n submit: () => Promise<boolean>;\\n /** Алиас `submit` для не-submit сценариев. */\\n validate: () => Promise<boolean>;\\n /** Идёт ли прогон (submit или live) — для блокировки кнопки. */\\n isValidating: boolean;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/platforms/react/hooks/use-form-validation.ts","entries":["."],"package":"@reformer/core"},{"name":"validate","kind":"function","signature":"export function validate<TField>(sig: PathAwareSignal<TField>, rules: Rule<TField>[]): void","summary":"Синхронные правила поля.","description":"Синхронные правила поля.","params":[],"example":"```ts\\nvalidate(model.$.loanAmount, [required({ message: \'Сумма\' }), min(50000)]);\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-patterns","common-mistakes","complete-import","formschema","arrays","multi-step","extended-mistakes","nonexistent-api","conditional-fields","submit-and-reset","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/validation/operators.ts","entries":["./validation"],"package":"@reformer/core","usage":145},{"name":"validateAsync","kind":"function","signature":"export function validateAsync<TField>(\\n sig: PathAwareSignal<TField>,\\n rules: AsyncRule<TField>[]\\n): void","summary":"Асинхронные правила поля (зеркалит движковое разделение `validators` / `asyncValidators`).","description":"Асинхронные правила поля (зеркалит движковое разделение `validators` / `asyncValidators`).\\nРаннер дожидается их и прокидывает `AbortSignal` для отмены устаревших ответов.","params":[],"example":"```ts\\nvalidateAsync(model.$.username, [async (v, { signal }) => {\\n const r = await fetch(`/api/free?u=${v}`, { signal });\\n return (await r.json()).free ? null : { code: \'taken\', message: \'Занято\' };\\n}]);\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-mistakes","complete-import","extended-mistakes","nonexistent-api","submit-and-reset","async-validator-debounce"],"sourcePath":"src/form/validation/operators.ts","entries":["./validation"],"package":"@reformer/core","usage":12},{"name":"validateModel","kind":"function","signature":"export async function validateModel<T>(\\n model: FormModel<T>,\\n schema: ValidationSchema<T>,\\n options?: { touch?: boolean }\\n): Promise<boolean>","summary":"Провалидировать модель ЛЮБОЙ схемой (шаг или вся форма).","description":"Провалидировать модель ЛЮБОЙ схемой (шаг или вся форма). Открывает ambient-окно на время\\nсинхронного прогона `schema`, дожидается async-правил, разносит ошибки по нодам формы и гасит\\nполя, ставшие валидными. Возвращает `true`, если нет блокирующих ошибок (`severity:\'warning\'` не блокирует).\\n\\nГашение — на пару (model, schema): `validateModel(model, step2)` и `validateModel(model, form)` не мешают\\nдруг другу. Устаревший прогон (быстрый повторный вызов той же (model, schema)) отменяется через `AbortSignal`\\nи возвращает `false` (**fail-closed** — отменённому результату нельзя доверять для submit).\\n\\n⚠️ `schema` должна быть СТАБИЛЬНОЙ ссылкой: отмена устаревших прогонов ключится по идентичности `schema`.\\nИнлайн-стрелка (`validateModel(model, ({ model }) => …)`) каждый раз создаёт НОВЫЙ прогон без дедупликации —\\nдержите схемы в `const` / `defineValidationSchema`.\\n\\n`options.touch` (§6): по завершении помечает `touched` ИМЕННО поля, которые схема проверяла\\n(не всё поддерево). Ошибки становятся видимыми (`shouldShowError = invalid && (touched||dirty)`)\\nбез ручного `form.markAsTouched()`; при пошаговой валидации следующий шаг не показывается\\n«тронутым» до ввода. Валидные проверенные поля тоже метятся — это безвредно (ошибка не покажется).","params":[["model","- Модель данных формы."],["schema","- Схема валидации (стабильная ссылка)."],["options","- `{ touch }` — пометить провалидированные поля `touched` для показа ошибок."]],"example":"```ts\\nconst ok = await validateModel(model, step2Validation); // один шаг\\nconst all = await validateModel(model, formValidation); // вся форма\\nconst stepOk = await validateModel(model, step2Validation, { touch: true }); // + показать ошибки шага\\n```","examplesCount":1,"topics":["api-reference","quick-start","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","formschema","arrays","multi-step","extended-mistakes","project-structure","nonexistent-api","conditional-fields","revalidate-when","submit-and-reset","async-preload","type-safety-recipes","async-validator-debounce","validation-strategy"],"sourcePath":"src/form/validation/run.ts","entries":["./validation"],"package":"@reformer/core","usage":28},{"name":"ValidateOptions","kind":"interface","signature":"export interface ValidateOptions {\\n /** Готовое сообщение об ошибке. Если не задано, валидаторы кладут `\'\'`, и отображаемый текст\\n * резолвится из `code` (см. резолвер сообщений в `@reformer/cdk`). */\\n message?: string;\\n /** Параметры ошибки (подстановка в шаблон сообщения / i18n). */\\n params?: Record<string, FormValue>;\\n}","summary":"Опции валидатора-фабрики (`required()`/`pattern()`/…).","description":"Опции валидатора-фабрики (`required()`/`pattern()`/…). Передаются вторым (или последним)\\nаргументом в фабрику и попадают в возвращаемую {@link ValidationError}.","params":[],"examplesCount":0,"sourcePath":"src/form/types/validation-schema.ts","entries":["."],"package":"@reformer/core"},{"name":"validateWhen","kind":"function","signature":"export function validateWhen(cond: () => boolean, cb: () => void): void","summary":"Условная валидация: правила внутри `cb` активны, только пока `cond()` истинно; иначе их поля ГАСЯТСЯ (пустой bucket → `setErrors([])`).","description":"Условная валидация: правила внутри `cb` активны, только пока `cond()` истинно; иначе их поля\\nГАСЯТСЯ (пустой bucket → `setErrors([])`). Не трогает включение/сброс поля — это дело поведения (`enableWhen`).","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","extended-mistakes","nonexistent-api","conditional-fields","submit-and-reset"],"sourcePath":"src/form/validation/operators.ts","entries":["./validation"],"package":"@reformer/core","usage":8},{"name":"ValidationError","kind":"interface","signature":"export interface ValidationError {\\n code: string;\\n message: string;\\n params?: Record<string, FormValue>;\\n /** Severity level: \'error\' (default) blocks submission, \'warning\' shows message but allows submission */\\n severity?: \'error\' | \'warning\';\\n}","summary":"Ошибка валидации","description":"Ошибка валидации","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","extended-mistakes","nonexistent-api","conditional-fields","array-operations","revalidate-when","type-safety-recipes","async-validator-debounce"],"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core","usage":24},{"name":"ValidationSchema","kind":"type","signature":"export type ValidationSchema<T> = (ctx: { model: FormModel<T> }) => void;","summary":"Схема валидации — обычная функция над (под)моделью.","description":"Схема валидации — обычная функция над (под)моделью. First-class значение (можно `apply`/тестировать/переиспользовать).","params":[],"examplesCount":0,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","complete-import","multi-step","nonexistent-api","conditional-fields","submit-and-reset","validation-strategy"],"sourcePath":"src/form/validation/types.ts","entries":["./validation"],"package":"@reformer/core","usage":8},{"name":"ValidationStrategyKind","kind":"type","signature":"export type ValidationStrategyKind = \'submit\' | \'blur\' | \'change\' | \'afterFirstSubmit\';","summary":"Когда запускается schema-валидация: - `submit` (по умолчанию) — только явным вызовом `validate()` (на отправке); - `blur` — при потере фокуса поля (смена `touched` любого листа); - `change` — на каждый ввод (с опц.","description":"Когда запускается schema-валидация:\\n- `submit` (по умолчанию) — только явным вызовом `validate()` (на отправке);\\n- `blur` — при потере фокуса поля (смена `touched` любого листа);\\n- `change` — на каждый ввод (с опц. `debounce`);\\n- `afterFirstSubmit` — тихо до первого `validate()`, затем live (см. `liveAfterSubmit`).","params":[],"examplesCount":0,"topics":["validation-strategy"],"sourcePath":"src/form/validation/strategy.ts","entries":["./validation"],"package":"@reformer/core"},{"name":"ValidationStrategyOptions","kind":"interface","signature":"export interface ValidationStrategyOptions {\\n /** Стратегия запуска. Default `\'submit\'`. */\\n strategy?: ValidationStrategyKind;\\n /** Debounce (мс) для live-фаз (`change` и live-часть `afterFirstSubmit`). Default `0`. */\\n debounce?: number;\\n /** Режим live-фазы для `afterFirstSubmit`. Default `\'change\'`. */\\n liveAfterSubmit?: \'change\' | \'blur\';\\n}","summary":"","params":[],"examplesCount":0,"topics":["validation-strategy"],"sourcePath":"src/form/validation/strategy.ts","entries":["./validation"],"package":"@reformer/core"},{"name":"Validator","kind":"type","signature":"export type Validator<TForm, TField> = (\\n value: TField,\\n scope: unknown,\\n root: FormModel<TForm>\\n) => ValidationError | null;","summary":"Чистый синхронный валидатор поля (legacy-сигнатура `(value, scope, root)`).","description":"Чистый синхронный валидатор поля (legacy-сигнатура `(value, scope, root)`).","params":[],"examplesCount":0,"deprecated":"Осиротевший остаток удалённого дерево-движка (`validateFormModel`). Живой контракт —\\n`Rule<T> = (value) => ValidationError | null` из `@reformer/core/validation`: правила\\nпередаются в `validate(sig, [rules])` внутри `defineValidationSchema` и запускаются\\n`validateModel(model, schema)`. Cross-field — оператор `cross(sig, (f) => …)` над снапшотом\\n`model.get()` (третий аргумент `root` больше не нужен). Тип экспортируется только ради\\nобратной совместимости (`SchemaValidator`-union).","sourcePath":"src/form/types/validation-schema.ts","entries":["."],"package":"@reformer/core"},{"name":"ValidatorFn","kind":"type","signature":"export type ValidatorFn<T = FormValue> = (value: T) => ValidationError | null;","summary":"Синхронная функция валидации","description":"Синхронная функция валидации","params":[],"examplesCount":0,"sourcePath":"src/form/types/contracts.ts","entries":["."],"package":"@reformer/core"},{"name":"watchField","kind":"function","signature":"export function watchField<T>(\\n source: ReadonlySignal<T>,\\n cb: (value: T) => void,\\n options?: { immediate?: boolean }\\n): BehaviorCleanup","summary":"Реакция на изменение поля: вызывает `cb(value)` при каждом изменении (по умолчанию без вызова на инициализации; `immediate: true` — вызвать сразу).","description":"Реакция на изменение поля: вызывает `cb(value)` при каждом изменении (по умолчанию без вызова на\\nинициализации; `immediate: true` — вызвать сразу).","params":[],"example":"```typescript\\nwatchField(model.$.country, async (country) => {\\n model.city = \'\';\\n // ... загрузить города\\n});\\n```","examplesCount":1,"topics":["api-reference","api-signatures","common-patterns","common-mistakes","troubleshooting","complete-import","async-watchfield","reading-values","compute-vs-watch","sync-fields","type-safety-recipes"],"sourcePath":"src/model/behaviors-value.ts","entries":[".","./model"],"package":"@reformer/core","usage":4}]},"@reformer/cdk":{"schemaVersion":1,"package":"@reformer/cdk","version":"6.0.0","topics":[{"id":"overview","file":"01-overview.md","title":"Overview","purpose":"`@reformer/cdk` provides headless UI components for `@reformer/core` forms.","keyConcepts":["**Headless**: No default UI or styles - you build the interface","**Compound Components**: Composable, declarative API","**Render Props**: Children as function for full control","**Context-based**: State shared via React Context"],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Key Concepts","slug":"key-concepts"},{"heading":"Components","slug":"components"},{"heading":"Installation","slug":"installation"},{"heading":"Import Patterns","slug":"import-patterns"}],"terms":[["reformer",9],["cdk",7],["import",6],["form",5],["from",5],["components",4],["asyncboundary",3],["formarray",3],["formfield",3],["formwizard",3],["headless",2],["for",2],["core",2],["control",2],["context",2],["loading",2],["field",2],["wizard",2]]},{"id":"form-array","file":"02-form-array.md","title":"FormArray","purpose":"Headless compound component for managing form arrays.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Basic Usage","slug":"basic-usage"},{"heading":"Sub-components","slug":"sub-components"},{"heading":"List Render Props","slug":"list-render-props"},{"heading":"Typed item access (avoid `FormProxy<object>`)","slug":"typed-item-access-avoid-formproxy-object"},{"heading":"External Control via Ref","slug":"external-control-via-ref"},{"heading":"FormArrayHandle API","slug":"formarrayhandle-api"},{"heading":"useFormArray Hook","slug":"useformarray-hook"}],"terms":[["control",39],["formarray",30],["item",24],["the",17],["number",16],["items",15],["list",15],["void",14],["form",13],["index",13],["from",12],["array",12],["remove",11],["formproxy",11],["type",11],["button",10],["add",10],["typed",10],["length",9],["div",8],["useformarray",8],["tsx",7],["render",7],["move",7],["for",6],["import",6],["reformer",6],["root",6],["current",6],["formfield",6],["arrayref",6],["compound",5],["cdk",5],["empty",5],["onclick",5],["partial",5],["state",5],["object",5],["you",5],["and",5],["formarraysection",5],["value",5],["swap",5],["isempty",5],["key",4],["reactnode",4],["when",4],["one",4],["boolean",4],["not",4],["fields",4],["property",4],["kit",4],["const",4],["formarrayhandle",4],["preserved",4],["headless",3],["addbutton",3],["props",3],["count",3],["typescript",3],["interface",3],["reorder",3],["access",3],["inferred",3],["prop",3],["itemcomponent",3],["hook",3],["ref",3],["clear",3],["component",2],["itemform",2],["components",2],["arraynode",2],["context",2],["children",2],["initialvalue",2],["new",2],["inside",2],["displays",2],["moveup",2],["position",2],["movedown",2],["without",2],["its",2],["which",2],["any",2],["element",2],["jsx",2],["tag",2],["react",2],["does",2],["canonical",2],["propertyform",2],["properties",2],["full",2],["every",2],["explicit",2],["argument",2],["function",2],["return",2],["map",2],["via",2],["useref",2],["outside",2],["removeat",2],["insert",2],["two",2],["span",2],["useformarrayreturn",2],["order",2]]},{"id":"form-navigation","file":"03-form-navigation.md","title":"FormWizard","purpose":"Headless compound component for multi-step form wizards.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Basic Usage","slug":"basic-usage-2"},{"heading":"Sub-components","slug":"sub-components-2"},{"heading":"FormWizard.Indicator","slug":"formwizard-indicator"},{"heading":"FormWizard.Actions","slug":"formwizard-actions"},{"heading":"FormWizard.Progress","slug":"formwizard-progress"},{"heading":"External Control via Ref","slug":"external-control-via-ref-2"},{"heading":"Configuration","slug":"configuration"},{"heading":"Building config from step selectors: `defineSteps`","slug":"building-config-from-step-selectors-definesteps"},{"heading":"Живая валидация шага: `strategy` + `useWizardStepValidation`","slug":"zhivaya-validatsiya-shaga-strategy-usewizardstepvalidation"}],"terms":[["step",53],["formwizard",49],["the",34],["submit",34],["boolean",24],["form",23],["next",20],["config",19],["onclick",19],["button",18],["disabled",18],["number",17],["actions",16],["prev",15],["not",12],["reformer",11],["model",11],["strategy",11],["validatemodel",10],["validation",10],["and",10],["current",10],["from",9],["validatestep",9],["steps",9],["rules",9],["шага",9],["compound",8],["component",8],["tsx",8],["schema",8],["validateall",8],["null",8],["definesteps",8],["formwizardconfig",7],["wizard",7],["div",7],["are",7],["returns",6],["promise",6],["const",6],["step_schemas",6],["control",6],["isfirststep",6],["islaststep",6],["root",6],["render",6],["props",6],["typescript",6],["interface",6],["navref",6],["usewizardstepvalidation",6],["import",5],["cdk",5],["core",5],["onsubmit",5],["they",5],["indicator",5],["progress",5],["currentstep",5],["with",5],["callbacks",4],["true",4],["valid",4],["fullschema",4],["back",4],["issubmitting",4],["level",4],["gotostep",4],["based",4],["string",4],["percent",4],["selector",4],["loan",4],["applicant",4],["confirm",4],["blur",4],["change",4],["headless",3],["for",3],["schemas",3],["each",3],["errors",3],["result",3],["handlesubmit",3],["that",3],["explicitly",3],["navigation",3],["inside",3],["title",3],["isvalidating",3],["void",3],["total",3],["ref",3],["validate",3],["node",3],["definevalidationschema",3],["apply",3],["per",3],["index",3],["step1",3],["step2",3],["crossfieldrules",3],["extras",3],["внутри",3],["активного",3],["слой",3],["поля",3],["pair",2],["routes",2],["into",2],["itself",2],["just",2],["its",2],["has",2],["them",2],["read",2],["members",2],["shown",2],["children",2],["submitting",2],["nav",2],["key",2],["cannavigate",2],["iscurrent",2],["iscompleted",2],["icon",2],["formwizardindicatorstepwithstate",2],["values",2],["return",2],["missing",2],["both",2],["over",2],["validationschema",2],["see",2],["docs",2],["plain",2],["composes",2],["never",2],["directly",2],["runs",2],["markastouched",2],["stays",2],["same",2],["selectors",2],["position",2],["reordering",2],["instead",2],["order",2],["declared",2],["only",2],["loanstep",2],["stepselectors",2],["createstepcontroller",2],["live",2],["touched",2],["visible",2],["далее",2],["debounce",2],["liveaftersubmit",2],["что",2],["afterfirstsubmit",2],["для",2],["живой",2],["при",2],["смене",2],["unmount",2]]},{"id":"form-field","file":"04-form-field.md","title":"FormField","purpose":"- Дать минимальный «скелет» поля: label + control + description + error. - Не навязывать стилей — каждый sub-компонент рендерит обычные HTML-элементы (или `Slot` через `asChild`). - Подписаться на `FieldNode` ровно один раз в `Root` и раздать состояние детям через React Context. - Гарантировать корректные ARIA-атрибуты в нетривиальных сценариях (multi-error, отсутствие label, async pending).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Использовать `FormField.Label` / `Error` / `Control` без `FormField.Root`.** Каждый дочерний компонент вызывает `useFormFieldContext()` и бросает: `FormField.* components must be used within <FormField.Root>`.\\n- **Подписываться на `useFormControl(control)` рядом с `FormField.Root`.** `Root` уже подписан — лишняя подписка приведёт к двойному ререндеру. Используйте `useFormFieldContext()` для доступа к состоянию.\\n- **Передавать `id` руками в `Control` / `Label`.** ID назначаются автоматически из `useId()`. Если нужен предсказуемый ID для тестов, передайте `id=\\"my-field\\"` в `Root` — все потомки получат `control-my-field`, `label-my-field`, …\\n- **Забывать `hasDescription` при наличии `FormField.Description`.** Без флага `Control` не пропишет `aria-describedby={descriptionId}`, и screen reader не зачитает helper-текст.\\n- **Двойное рендерание ошибки (`Error` + ручной `<p>`).** `FormField.Error` уже подписан на `errors`/`shouldShowError`. Если нужен кастомный layout — используйте `render` prop, а не дублируйте.\\n- **Применять `asChild` к компоненту, который не пробрасывает `ref`/`...props`.** `Slot` объединяет пропсы и ref в дочерний элемент; если потомок их не принимает, `aria-*`-атрибуты потеряются."}],"examples":[],"troubleshooting":["**`Error: FormField.* components must be used within <FormField.Root>`.** Проверьте, что вызов `FormField.Label` / `Control` / `Error` обёрнут в `FormField.Root` и компонент не рендерится в портале выше провайдера.","**`Label` ничего не показывает.** В схеме поля нет `componentProps.label`. Вариант: задайте `label` в схеме, или передайте `children` в `FormField.Label`, или поставьте `forceRender`.","**`Control` рендерит «голый» `<input>` без стилей.** Auto-mode рендерит `control.component` — убедитесь, что в схеме указан компонент (`component: InputField`). Иначе используйте `asChild` + свой компонент.","**Сырой контрол с event-диалектом (Checkbox/Radio) пишет в модель `event` вместо значения.** И auto-mode, и `asChild` вешают value-based seam (`value` + `onChange(value)` + `onBlur`). Контрол с диалектом `checked` + `onChange(event)` получит `value`, но в `setValue` уйдёт DOM-`event`. (`Select` с `onChange(value, option)` привязывается корректно сам — значение идёт первым аргументом, а лишний `option` обработчик отбрасывает; адаптер ему нужен, только если значение надо вывести ИЗ `option`/props, либо чтобы снять утечку пропа `control` в DOM.) Решение на уровне CDK: `asChild` с value-based обёрткой (переложите `event.target.checked` в `onChange(value)` руками) либо регистрация value-based обёртки как `component:` в схеме. Когда поле рисует не CDK-compound, а рендерер (`@reformer/renderer-react` / `@reformer/renderer-json`) из схемы — сырые контролы подключаются без обёрток через `RendererSettings.resolveFieldAdapter` (`FieldAdapter`: `valueProp`/`fromEmit`/`toValue`).","**`aria-describedby` пустой при наличии `Description`.** Не передан `hasDescription` в `Root`. Это не «магический» флаг — без него `Control` не знает, что description есть в дереве.","**`FormField.Error` не появляется при наличии ошибки.** Поле не помечено как touched. Используйте `form.markAsTouched()` или `control.markAsTouched()` перед сабмитом, либо настройте `revalidateWhen` чтобы помечать touched по `change`.","**При async-валидации индикатор моргает.** `pending` переключается на каждый `setValue`. Дебаунсьте источник или добавьте задержку перед показом спиннера (например, `useDeferredValue`).","**Дубликаты `id` в DOM.** Несколько `FormField.Root` с одинаковым явным `id`. Опустите `id` (тогда работает `useId()`) или дайте уникальные значения."],"seeAlso":["[01-overview.md](01-overview.md) — общее введение в `@reformer/cdk`.","[02-form-array.md](02-form-array.md), [03-form-navigation.md](03-form-navigation.md) — соседние compound-компоненты.","[06-recipes.md](06-recipes.md) — продвинутые паттерны (включая собственный wrapper над FormField).","[07-troubleshooting.md](07-troubleshooting.md) — типичные ошибки FormField/FormArray/FormWizard.","[src/components/form-field/](../../src/components/form-field/) — исходники compound-блоков и `useFormField`."],"sections":[{"heading":"Purpose","slug":"purpose"},{"heading":"Components","slug":"components-2"},{"heading":"Examples","slug":"examples"},{"heading":"Anti-patterns","slug":"anti-patterns"},{"heading":"Troubleshooting","slug":"troubleshooting"},{"heading":"See also","slug":"see-also"}],"terms":[["formfield",56],["control",38],["label",24],["root",23],["form",19],["error",15],["aria",14],["reformer",12],["classname",12],["value",11],["для",9],["cdk",9],["aschild",8],["без",8],["field",8],["div",8],["text",8],["component",7],["description",7],["компонент",7],["рендерит",7],["или",7],["нужен",7],["если",7],["fieldroot",7],["compound",6],["describedby",6],["onchange",6],["через",6],["pending",6],["kit",6],["hasdescription",6],["componentprops",6],["useformfieldcontext",6],["email",6],["layout",5],["components",5],["текст",5],["при",5],["используйте",5],["чтобы",5],["auto",5],["tsx",5],["import",5],["from",5],["схеме",5],["event",5],["поля",4],["multi",4],["async",4],["когда",4],["children",4],["errors",4],["dom",4],["input",4],["ошибки",4],["a11y",3],["required",3],["состояние",3],["fieldnode",3],["onblur",3],["каждый",3],["slot",3],["один",3],["атрибуты",3],["который",3],["нет",3],["дочерний",3],["mode",3],["render",3],["поле",3],["touched",3],["ids",3],["descriptionid",3],["передайте",3],["return",3],["items",3],["gap",3],["flex",3],["уже",3],["наличии",3],["troubleshooting",3],["что",3],["based",3],["option",3],["либо",3],["формы",2],["htmlfor",2],["errormessage",2],["сами",2],["purpose",2],["стилей",2],["раз",2],["react",2],["context",2],["ошибка",2],["ничего",2],["требуется",2],["собственный",2],["принимает",2],["useformcontrol",2],["индикатор",2],["возвращает",2],["null",2],["forcerender",2],["пустой",2],["пропсами",2],["элемент",2],["disabled",2],["рендерится",2],["shouldshowerror",2],["автоматически",2],["прописал",2],["бросает",2],["useformfield",2],["над",2],["function",2],["select",2],["обёртки",2],["helper",2],["grid",2],["gray",2],["red",2],["валидации",2],["pendingdot",2],["username",2],["center",2],["все",2],["например",2],["получит",2],["свой",2],["кастомный",2],["must",2],["used",2],["within",2],["подписан",2],["руками",2],["useid",2],["ref",2],["props",2],["контрол",2],["диалектом",2],["значения",2],["checked",2],["setvalue",2],["значение",2],["как",2],["renderer",2],["markastouched",2],["перед",2],["overview",2],["array",2],["navigation",2],["recipes",2],["src",2]]},{"id":"async-boundary","file":"05-async-boundary.md","title":"AsyncBoundary","purpose":"- Забрать загрузку внутрь компонента: снаружи остаются только «как загрузить» (`load`) и «что сделать с ответом» (`onSuccess`), а гонки, отмена и повтор — внутри. - Развести четыре взаимоисключающих состояния экрана без цепочки тернарников. - Передать в слот ошибки **саму ошибку и колбэк повтора** — чтобы текст сбоя не приходилось хардкодить в отдельном компоненте-обёртке. - Отличить «грузить нечего» (`idle`) от «успешно загружено» (`ready`). - Погасить вспышку спиннера при быстром ответе (`delayMs`) и сохранить контент при фоновом обновлении (`refreshing`). - Выдать корректные `aria-busy` / `role=\\"status\\"` / `role=\\"alert\\"` без участия консумента.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Не** заводить пятый статус `\'empty\'`: пустоту знает только консумент, а статус пришлось бы пересчитывать на каждое изменение данных. Используйте `AsyncBoundary.Empty` с `when`.\\n- **Не** схлопывать «нечего грузить» в `ready` — для этого есть `idle`.\\n- **Не** рендерить кнопку повтора без рабочего `onRetry`: она ловит фокус и читается скринридером впустую. `AsyncBoundary.Retry` скрывается сам.\\n- **Не** смешивать режимы: если передан `load`, не передавайте ещё и `status` — компонент его игнорирует, а читающий код будет думать, что состояние приходит снаружи.\\n- **Не** забывать `AbortSignal` в `load`: без него отменённый запрос доедет до сервера и продолжит держать соединение, а гонку поймает только внутренний guard.\\n- **Не** передавать в `loadKey` свежий объект (`{ id }`) — сравнение идёт по `Object.is`, и загрузка перезапустится на каждом рендере. Нужен примитив или мемоизированное значение.\\n- **Не** переиспользовать слово `pending` для загрузки данных — в `@reformer/core` оно занято состоянием асинхронного валидатора (`FieldStatus === \'pending\'`).\\n- **Не** класть в CDK-слоты Tailwind-классы и вёрстку: стилизованные блоки живут в `@reformer/ui-kit` (`AsyncBoundary`, `AsyncBoundaryLoading`, `AsyncBoundaryError`, `AsyncBoundaryEmpty`)."}],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Два режима","slug":"dva-rezhima"},{"heading":"Purpose","slug":"purpose-2"},{"heading":"Components","slug":"components-3"},{"heading":"Imperative handle","slug":"imperative-handle"},{"heading":"Examples","slug":"examples-2"},{"heading":"Accessibility","slug":"accessibility"},{"heading":"Common Patterns","slug":"common-patterns"},{"heading":"Anti-patterns","slug":"anti-patterns-2"}],"terms":[["asyncboundary",45],["error",25],["status",25],["root",13],["idle",12],["button",12],["при",11],["без",11],["retry",11],["aria",10],["для",9],["loading",9],["load",9],["refreshing",9],["загрузка",9],["content",9],["ready",8],["onretry",8],["role",8],["data",8],["delayms",7],["reload",7],["applicationid",7],["form",7],["reformer",6],["содержимое",6],["tsx",6],["live",6],["div",6],["загрузки",5],["состояние",5],["запрос",5],["loadkey",5],["props",5],["только",5],["empty",5],["onclick",5],["данных",4],["это",4],["boundary",4],["self",4],["managed",4],["controlled",4],["режиме",4],["его",4],["что",4],["внутри",4],["грузить",4],["нечего",4],["alert",4],["null",4],["false",4],["useasyncboundary",4],["rootprops",4],["loadingprops",4],["errorprops",4],["import",4],["from",4],["cdk",4],["boundaryref",4],["isloading",4],["заявка",4],["compound",3],["ничего",3],["режим",3],["передан",3],["консумент",3],["как",3],["повтора",3],["остаётся",3],["приходит",3],["when",3],["children",3],["или",3],["canretry",3],["хук",3],["abort",3],["asyncboundaryhandle",3],["async",3],["function",3],["return",3],["polite",3],["assertive",3],["string",3],["повторить",3],["item",3],["iserror",3],["статус",3],["component",2],["состояний",2],["рендерит",2],["разметки",2],["kit",2],["два",2],["компонент",2],["сам",2],["отменяет",2],["даёт",2],["повтор",2],["purpose",2],["загрузку",2],["компонента",2],["снаружи",2],["onsuccess",2],["слот",2],["ошибки",2],["текст",2],["успешно",2],["быстром",2],["ответе",2],["контент",2],["обновлении",2],["busy",2],["принимает",2],["слоты",2],["форма",2],["создания",2],["когда",2],["данные",2],["рендерится",2],["значение",2],["render",2],["кнопка",2],["type",2],["флаги",2],["ids",2],["вне",2],["options",2],["вручную",2],["enabled",2],["react",2],["handle",2],["ref",2],["дерева",2],["обновить",2],["useref",2],["const",2],["header",2],["current",2],["прервать",2],["applicationpage",2],["signal",2],["новая",2],["заявки",2],["creditform",2],["abortsignal",2],["иначе",2],["отменённый",2],["продолжит",2],["поэтому",2],["ответ",2],["состоянием",2],["код",2],["пустоту",2],["она",2],["items",2],["section",2],["регион",2],["чтение",2],["patterns",2],["pending",2]]},{"id":"recipes","file":"06-recipes.md","title":"Advanced Recipes","purpose":"Готовые рецепты для нетривиальных задач: вложенные массивы, кастомный AddButton, динамическое количество шагов в wizard, externally-controlled wizard. Каждый рецепт — Problem → Solution → Notes.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-form-array.md](02-form-array.md) — основы FormArray (compound API, ref-handle).","[03-form-navigation.md](03-form-navigation.md) — основы FormWizard (Indicator, Actions, Progress).","[04-form-field.md](04-form-field.md) — компоновка одного поля.","[07-troubleshooting.md](07-troubleshooting.md) — типичные ошибки и пути их обхода."],"sections":[{"heading":"Nested FormArray","slug":"nested-formarray"},{"heading":"Custom AddButton","slug":"custom-addbutton"},{"heading":"Conditional / dynamic step count in FormWizard","slug":"conditional-dynamic-step-count-in-formwizard"},{"heading":"Externally-controlled wizard via `useRef<FormWizardHandle>`","slug":"externally-controlled-wizard-via-useref-formwizardhandle"},{"heading":"See also","slug":"see-also-2"}],"terms":[["form",34],["formarray",27],["formwizard",25],["control",21],["step",19],["button",17],["menu",13],["list",12],["classname",12],["root",11],["import",10],["from",10],["onclick",10],["если",10],["const",10],["reformer",9],["submit",9],["addbutton",8],["config",8],["component",8],["property",7],["type",7],["item",7],["add",7],["шаг",7],["navref",7],["tsx",6],["return",6],["current",6],["needsverification",6],["disabled",6],["null",6],["wizard",5],["problem",5],["solution",5],["notes",5],["formfield",5],["completedsteps",5],["например",4],["properties",4],["имущество",4],["внутри",4],["cdk",4],["array",4],["index",4],["flex",4],["div",4],["useformarraycontext",4],["через",4],["ref",4],["useref",4],["validatemodel",4],["stepschemas",4],["validatestep",4],["validateall",4],["schema",4],["gotostep",4],["formwizardhandle",4],["для",3],["шагов",3],["каждый",3],["coowners",3],["чтобы",3],["remove",3],["owner",3],["btn",3],["добавить",3],["компонент",3],["react",3],["или",3],["function",3],["onselect",3],["value",3],["push",3],["схемы",3],["usememo",3],["core",3],["fullschema",3],["amount",3],["при",3],["model",3],["true",3],["actions",3],["onsubmit",3],["prev",3],["next",3],["islaststep",3],["либо",3],["currentstep",3],["api",3],["валидацией",3],["кастомный",2],["количество",2],["externally",2],["controlled",2],["нужно",2],["массивов",2],["совладельцы",2],["это",2],["достаточно",2],["space",2],["fieldset",2],["border",2],["legend",2],["justify",2],["between",2],["span",2],["estimatedvalue",2],["removeowner",2],["primary",2],["внутренний",2],["length",2],["массива",2],["useformarray",2],["внешний",2],["нужен",2],["рендер",2],["шаги",2],["compound",2],["addpropertymenu",2],["trigger",2],["content",2],["только",2],["снаружи",2],["поля",2],["можно",2],["живёт",2],["шапке",2],["страницы",2],["используйте",2],["handle",2],["вызывайте",2],["children",2],["верификация",2],["рендера",2],["totalsteps",2],["useformcontrol",2],["validation",2],["formwizardconfig",2],["props",2],["верификации",2],["boolean",2],["ошибки",2],["сам",2],["схему",2],["колбэк",2],["иначе",2],["как",2],["пока",2],["после",2],["перейти",2],["сохранить",2],["выйти",2],["переход",2],["handlesaveandexit",2],["async",2],["форма",2],["result",2],["await",2],["values",2],["jumptocontacts",2],["сначала",2],["header",2],["gotonextstep",2],["возвращает",2],["основы",2],["navigation",2],["field",2],["troubleshooting",2]]},{"id":"troubleshooting","file":"07-troubleshooting.md","title":"Troubleshooting / FAQ","purpose":"Типичные проблемы при использовании `@reformer/cdk` (FormField, FormArray, FormWizard) с краткими причинами и решениями.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md), [04-form-field.md](04-form-field.md), [06-recipes.md](06-recipes.md).","[@reformer/core troubleshooting](../../../reformer/docs/llms/) — общие проблемы с валидацией и behaviors."],"sections":[{"heading":"`FormArray.AddButton` не появляется на странице","slug":"formarray-addbutton-ne-poyavlyaetsya-na-stranitse"},{"heading":"`FormArray.List` ререндерит весь массив при изменении одного элемента","slug":"formarray-list-rerenderit-ves-massiv-pri-izmenenii-odnogo-elementa"},{"heading":"`FormWizardHandle.goToStep` возвращает `false`","slug":"formwizardhandle-gotostep-vozvraschaet-false"},{"heading":"Шаг без валидации пропускается без проверки","slug":"shag-bez-validatsii-propuskaetsya-bez-proverki"},{"heading":"`useFormArrayContext` бросает исключение","slug":"useformarraycontext-brosaet-isklyuchenie"},{"heading":"`useFormFieldContext` бросает исключение","slug":"useformfieldcontext-brosaet-isklyuchenie"},{"heading":"`FormField.Error` не показывает ошибку, хотя `errors.length > 0`","slug":"formfield-error-ne-pokazyvaet-oshibku-hotya-errors-length-0"},{"heading":"`FormField.Description` есть в DOM, но `aria-describedby` пустой","slug":"formfield-description-est-v-dom-no-aria-describedby-pustoy"},{"heading":"Multi-step submit срабатывает раньше валидации последнего шага","slug":"multi-step-submit-srabatyvaet-ranshe-validatsii-poslednego-shaga"},{"heading":"`FormArray.List` теряет focus или ререндерит inputs при `add`/`removeAt`","slug":"formarray-list-teryaet-focus-ili-rerenderit-inputs-pri-add-removeat"},{"heading":"`FormWizard` показывает «No validateStep callback configured for step N» в консоли","slug":"formwizard-pokazyvaet-no-validatestep-callback-configured-for-step-n-v-konsoli"},{"heading":"Ref `FormArrayHandle.length` / `isEmpty` не обновляется","slug":"ref-formarrayhandle-length-isempty-ne-obnovlyaetsya"},{"heading":"See also","slug":"see-also-3"}],"terms":[["formarray",23],["root",19],["control",18],["formfield",15],["причина",12],["решение",12],["если",11],["для",11],["submit",11],["form",10],["list",10],["step",8],["без",8],["validatestep",8],["при",7],["reformer",7],["tsx",7],["const",7],["шаг",7],["addbutton",6],["только",6],["или",6],["key",6],["валидации",6],["current",6],["config",6],["шага",6],["formwizard",5],["элемента",5],["item",5],["используйте",5],["await",5],["true",5],["boolean",5],["error",5],["внутри",4],["либо",4],["recipes",4],["items",4],["render",4],["который",4],["через",4],["react",4],["это",4],["navref",4],["validatecurrentstep",4],["return",4],["length",4],["например",3],["возвращает",3],["поля",3],["gotostep",3],["false",3],["totalsteps",3],["сам",3],["валидным",3],["formwizardconfig",3],["promise",3],["validateall",3],["core",3],["validatemodel",3],["schema",3],["снаружи",3],["label",3],["поле",3],["показывает",3],["markastouched",3],["description",3],["hasdescription",3],["обработчике",3],["troubleshooting",2],["проблемы",2],["рендерит",2],["кнопки",2],["поместите",2],["дерево",2],["вызывайте",2],["useformarraycontext",2],["add",2],["ререндерит",2],["массив",2],["массива",2],["useformcontrol",2],["memo",2],["стабильный",2],["useformarray",2],["поэтому",2],["уже",2],["также",2],["gotonextstep",2],["completed",2],["как",2],["вручную",2],["поверх",2],["проверки",2],["вызывает",2],["колбэк",2],["задан",2],["warn",2],["считается",2],["typescript",2],["схемы",2],["всё",2],["validation",2],["верните",2],["stepschemas",2],["model",2],["ошибки",2],["бросает",2],["исключение",2],["сообщение",2],["components",2],["must",2],["used",2],["within",2],["потребителя",2],["ref",2],["formarrayhandle",2],["null",2],["touched",2],["после",2],["формы",2],["validate",2],["handlesubmit",2],["async",2],["dom",2],["aria",2],["describedby",2],["последнего",2],["actions",2],["props",2],["stepok",2],["removeat",2],["index",2],["div",2],["arrayref",2],["overview",2],["field",2]]}],"symbols":[{"name":"AsyncBoundary","kind":"const","signature":"export const AsyncBoundary","summary":"AsyncBoundary — headless compound-компонент состояний асинхронной загрузки.","description":"AsyncBoundary — headless compound-компонент состояний асинхронной загрузки.\\n\\nРазделяет экран на четыре взаимоисключающих состояния (`idle` / `loading` / `ready` /\\n`error`) и раздаёт их слотам. Разметки и стилей не навязывает — визуальный слой живёт\\nв `@reformer/ui-kit`.\\n\\nЭто НЕ Suspense-boundary: ничего не бросается и не перехватывается, статусом управляет\\nконсумент. Сам компонент данные не грузит — он их только отображает.\\n\\n## Возможности\\n- **Headless** — ноль разметки, слоты возвращают голые фрагменты\\n- **Ошибка с контекстом** — слот `Error` получает саму ошибку и `retry` через render-функцию\\n- **Отложенный спиннер** — `delayMs` гасит вспышку загрузки при быстром ответе\\n- **Stale-while-revalidate** — `refreshing` оставляет контент на экране во время обновления\\n- **Готовая a11y** — `aria-busy` на регионе, `role=\\"status\\"`/`role=\\"alert\\"` на слотах\\n\\n## Слоты\\n- `AsyncBoundary.Root` — провайдер контекста, принимает `status`\\n- `AsyncBoundary.Idle` — загрузка не запускалась\\n- `AsyncBoundary.Loading` — идёт загрузка (с учётом `delayMs`)\\n- `AsyncBoundary.Content` — данные получены\\n- `AsyncBoundary.Empty` — данные получены, но пусты (предикат `when`)\\n- `AsyncBoundary.Error` — ошибка; render-функция получает `error` / `retry` / `canRetry`\\n- `AsyncBoundary.Retry` — кнопка повтора, скрыта без `onRetry`","params":[],"example":"Полное дерево состояний\\n```tsx\\nimport { AsyncBoundary } from \'@reformer/cdk/async-boundary\';\\n\\nfunction ApplicationPage({ status, error, reload, form }: Props) {\\nreturn (\\n<AsyncBoundary.Root status={status} error={error} onRetry={reload} delayMs={200}>\\n<AsyncBoundary.Loading>\\n<p role=\\"status\\" aria-live=\\"polite\\">Загрузка заявки…</p>\\n</AsyncBoundary.Loading>\\n\\n<AsyncBoundary.Error>\\n{({ error, retry }) => (\\n <div role=\\"alert\\" aria-live=\\"assertive\\">\\n <p>{String(error)}</p>\\n <button onClick={retry}>Повторить</button>\\n </div>\\n)}\\n</AsyncBoundary.Error>\\n\\n<AsyncBoundary.Content>\\n<CreditForm form={form} />\\n</AsyncBoundary.Content>\\n</AsyncBoundary.Root>\\n);\\n}\\n```","examplesCount":3,"related":["useAsyncBoundary"],"topics":["overview","async-boundary"],"sourcePath":"src/components/async-boundary/AsyncBoundary.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk","usage":29},{"name":"AsyncBoundaryContent","kind":"function","signature":"export function AsyncBoundaryContent<T = unknown>({\\n showWhileRefreshing = true,\\n children,\\n}: AsyncBoundaryContentProps<T>)","summary":"AsyncBoundary.Content — содержимое, видимое при успешной загрузке (`status === \'ready\'`).","description":"AsyncBoundary.Content — содержимое, видимое при успешной загрузке (`status === \'ready\'`).\\n\\nПо умолчанию остаётся на экране и во время фонового обновления (`refreshing`) —\\nэто stale-while-revalidate: пользователь не теряет контекст, пока грузится новая порция.\\nПередайте `showWhileRefreshing={false}`, если обновление должно скрывать контент.\\n\\nВ self-managed режиме `children` может быть render-функцией: она получает\\nзагруженные данные (внутри `ready` они гарантированно есть).","params":[],"example":"Статичный контент\\n```tsx\\n<AsyncBoundary.Content>\\n<CreditForm form={form} />\\n</AsyncBoundary.Content>\\n```","examplesCount":3,"sourcePath":"src/components/async-boundary/AsyncBoundaryContent.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryContentProps","kind":"interface","signature":"export interface AsyncBoundaryContentProps<T = unknown> {\\n /**\\n * Показывать контент во время фонового обновления (`refreshing`).\\n * @default true\\n */\\n showWhileRefreshing?: boolean;\\n /**\\n * Содержимое при `status === \'ready\'`. В self-managed режиме можно передать\\n * render-функцию — она получит загруженные данные уже суженными до `T`\\n * (внутри `ready` они гарантированно есть).\\n */\\n children: ReactNode | ((data: T) => ReactNode);\\n}","summary":"Props слота `AsyncBoundary.Content`.","description":"Props слота `AsyncBoundary.Content`.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryContext","kind":"const","signature":"export const AsyncBoundaryContext","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/AsyncBoundaryContext.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryContextValue","kind":"interface","signature":"export interface AsyncBoundaryContextValue<T = unknown, E = unknown> {\\n /** Сырой статус из `AsyncBoundary.Root`. */\\n status: AsyncStatus;\\n /**\\n * Загруженные данные — только в self-managed режиме (`load`). В controlled-режиме\\n * всегда `undefined`: там данными владеет консумент.\\n */\\n data: T | undefined;\\n /** `status === \'idle\'` — загрузка не запускалась. */\\n isIdle: boolean;\\n /**\\n * Показывать ли индикатор загрузки. Это НЕ `status === \'loading\'`: при `delayMs > 0`\\n * первые `delayMs` мс флаг остаётся `false`, чтобы быстрый ответ не вызывал вспышку спиннера.\\n */\\n isLoading: boolean;\\n /** `status === \'ready\'` — данные получены. */\\n isReady: boolean;\\n /** `status === \'error\'` — запрос упал. */\\n isError: boolean;\\n /** Фоновое обновление поверх уже показанного контента. */\\n refreshing: boolean;\\n /** Ошибка (null, когда её нет). */\\n error: E | null;\\n /** Повторить загрузку. В self-managed режиме перезапускает `load`. */\\n retry: () => void;\\n /** Возможен ли повтор: задан `onRetry` либо работает self-managed режим. */\\n canRetry: boolean;\\n /** Сгенерированные id для a11y-связок. */\\n ids: AsyncBoundaryIds;\\n /**\\n * Пропсы региона-обёртки (`aria-busy`, `data-status`). Лежат в контексте, а не только\\n * в {@link useAsyncBoundary}, чтобы обёртка из ui-kit не пересчитывала ту же логику:\\n * читать их можно только НИЖЕ провайдера, а сам `Root` разметки не рендерит.\\n */\\n rootProps: AsyncBoundaryRootPropGetters;\\n /** Пропсы индикатора загрузки: `role=\\"status\\"` + `aria-live=\\"polite\\"`. */\\n loadingProps: AsyncBoundaryLoadingPropGetters;\\n /** Пропсы блока ошибки: `role=\\"alert\\"` + `aria-live=\\"assertive\\"`. */\\n errorProps: AsyncBoundaryErrorPropGetters;\\n}","summary":"Значение контекста `AsyncBoundary`.","description":"Значение контекста `AsyncBoundary`. Слоты читают его и решают, рендериться ли им.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/AsyncBoundaryContext.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryEmpty","kind":"function","signature":"export function AsyncBoundaryEmpty({ when, children }: AsyncBoundaryEmptyProps)","summary":"AsyncBoundary.Empty — «данные загрузились, но их нет».","description":"AsyncBoundary.Empty — «данные загрузились, но их нет».\\n\\nПустота — отдельная от статуса ось: сам предикат знает только консумент\\n(пустой массив, `totalCount === 0`, отфильтрованная выборка), поэтому он приходит\\nпропом `when`, а слот лишь ограничивает его состоянием `ready`. Именно поэтому\\n`\'empty\'` не добавлен в {@link AsyncStatus} — иначе статус пришлось бы пересчитывать\\nна каждое изменение данных.","params":[],"example":"Пустой список после успешной загрузки\\n```tsx\\n<AsyncBoundary.Content>\\n<AsyncBoundary.Empty when={items.length === 0}>\\n<p>Ничего не найдено</p>\\n</AsyncBoundary.Empty>\\n{items.map(renderItem)}\\n</AsyncBoundary.Content>\\n```","examplesCount":1,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/AsyncBoundaryEmpty.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryEmptyProps","kind":"interface","signature":"export interface AsyncBoundaryEmptyProps {\\n /**\\n * Показать вместо контента, когда загрузка успешна, но данных нет.\\n * Пустота — ортогональная статусу ось: предикат считает консумент, а слот\\n * рендерится только внутри `ready`.\\n */\\n when: boolean;\\n /** Содержимое пустого состояния. */\\n children: ReactNode;\\n}","summary":"Props слота `AsyncBoundary.Empty`.","description":"Props слота `AsyncBoundary.Empty`.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryError","kind":"function","signature":"export function AsyncBoundaryError<E = unknown>({ children }: AsyncBoundaryErrorProps<E>)","summary":"AsyncBoundary.Error — содержимое, видимое при `status === \'error\'`.","description":"AsyncBoundary.Error — содержимое, видимое при `status === \'error\'`.\\n\\nЕдинственный слот с render-функцией: она получает саму ошибку и `retry`. Именно\\nотсутствие этих данных в props-less слотах прежнего API вынуждало консументов\\nоборачивать блок ошибки в замыкание с захардкоженным текстом и терять `onRetry`.","params":[],"example":"Render-функция с доступом к ошибке и повтору\\n```tsx\\n<AsyncBoundary.Error>\\n{({ error, retry, canRetry }) => (\\n<div role=\\"alert\\" aria-live=\\"assertive\\">\\n<p>{String(error)}</p>\\n{canRetry && <button onClick={retry}>Повторить</button>}\\n</div>\\n)}\\n</AsyncBoundary.Error>\\n```","examplesCount":2,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/AsyncBoundaryError.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryErrorPropGetters","kind":"interface","signature":"export interface AsyncBoundaryErrorPropGetters {\\n id: string;\\n role: \'alert\';\\n \'aria-live\': \'assertive\';\\n}","summary":"Пропсы блока ошибки.","description":"Пропсы блока ошибки.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryErrorProps","kind":"interface","signature":"export interface AsyncBoundaryErrorProps<E = unknown> {\\n /** Узел или render-функция, получающая `error` / `retry` / `canRetry`. */\\n children: ReactNode | ((props: AsyncBoundaryErrorRenderProps<E>) => ReactNode);\\n}","summary":"Props слота `AsyncBoundary.Error`.","description":"Props слота `AsyncBoundary.Error`.\\n\\nВ отличие от остальных слотов принимает render-функцию: именно потеря `error` и\\n`onRetry` в props-less слотах старого `AsyncBoundary` заставляла консументов писать\\nобёртки вида `() => <ErrorState error=\\"Не удалось загрузить\\" />` с захардкоженным текстом.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryErrorRenderProps","kind":"interface","signature":"export interface AsyncBoundaryErrorRenderProps<E = unknown> {\\n /** Ошибка из `AsyncBoundary.Root`. */\\n error: E | null;\\n /** Повторить загрузку (no-op, если `onRetry` не задан). */\\n retry: () => void;\\n /** Задан ли `onRetry` — по нему решают, рисовать ли кнопку повтора. */\\n canRetry: boolean;\\n}","summary":"Данные, которые `AsyncBoundary.Error` передаёт в render-функцию.","description":"Данные, которые `AsyncBoundary.Error` передаёт в render-функцию.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryHandle","kind":"interface","signature":"export interface AsyncBoundaryHandle<T = unknown, E = unknown> {\\n /** Перезапустить загрузку. В controlled-режиме вызывает `onRetry`. */\\n reload: () => void;\\n /** Прервать текущий запрос. Прерывание не считается ошибкой. В controlled-режиме — no-op. */\\n abort: () => void;\\n /** Снимок статуса на момент рендера. */\\n status: AsyncStatus;\\n /** Последние загруженные данные (только self-managed режим). */\\n data: T | undefined;\\n /** Снимок ошибки. */\\n error: E | null;\\n /** Идёт ли загрузка (с учётом `delayMs`). */\\n isLoading: boolean;\\n /** Идёт ли фоновое обновление. */\\n refreshing: boolean;\\n}","summary":"Императивный handle `AsyncBoundary`, доступный через `ref`.","description":"Императивный handle `AsyncBoundary`, доступный через `ref`.\\n\\nНужен, когда триггер перезагрузки живёт вне дерева границы: тулбар страницы,\\nпункт меню «Обновить», WebSocket-событие, кнопка в диалоге. Получают через\\n`useRef<AsyncBoundaryHandle<T>>(null)` и передают в `<AsyncBoundary.Root ref={...}>`.\\n\\nПоля `status` / `data` / `error` / `isLoading` / `refreshing` — снимок на момент\\nрендера. Для реактивного UI читайте их из {@link AsyncBoundaryContextValue}\\n(через слоты или `useAsyncBoundaryContext()`), а не из handle.","params":[],"example":"Кнопка «Обновить» в шапке страницы\\n```tsx\\nimport { useRef } from \'react\';\\nimport { AsyncBoundary, type AsyncBoundaryHandle } from \'@reformer/cdk/async-boundary\';\\n\\nfunction ApplicationsPage() {\\nconst boundaryRef = useRef<AsyncBoundaryHandle<Application[]>>(null);\\n\\nreturn (\\n<>\\n<header>\\n<button onClick={() => boundaryRef.current?.reload()}>Обновить</button>\\n<button onClick={() => boundaryRef.current?.abort()}>Отменить</button>\\n</header>\\n\\n<AsyncBoundary.Root ref={boundaryRef} load={(signal) => fetchApplications(signal)}>\\n<AsyncBoundary.Loading>Загрузка…</AsyncBoundary.Loading>\\n<AsyncBoundary.Content>{(items) => <List items={items} />}</AsyncBoundary.Content>\\n</AsyncBoundary.Root>\\n</>\\n);\\n}\\n```","examplesCount":2,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryIdle","kind":"function","signature":"export function AsyncBoundaryIdle({ children }: AsyncBoundarySlotProps)","summary":"AsyncBoundary.Idle — содержимое, видимое когда загрузка не запускалась (`status === \'idle\'`).","description":"AsyncBoundary.Idle — содержимое, видимое когда загрузка не запускалась (`status === \'idle\'`).\\n\\nТиповой случай — форма создания: записи ещё нет, грузить нечего, но и «успешной\\nзагрузкой» это состояние называть нельзя. Без отдельного слота консументы схлопывают\\nего в `ready` и теряют возможность показать другой заголовок или подсказку.","params":[],"example":"Разный заголовок для создания и редактирования\\n```tsx\\n<AsyncBoundary.Root status={applicationId ? status : \'idle\'}>\\n<AsyncBoundary.Idle><h1>Новая заявка</h1></AsyncBoundary.Idle>\\n<AsyncBoundary.Content><h1>Заявка №{applicationId}</h1></AsyncBoundary.Content>\\n</AsyncBoundary.Root>\\n```","examplesCount":1,"sourcePath":"src/components/async-boundary/AsyncBoundaryIdle.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryIds","kind":"interface","signature":"export interface AsyncBoundaryIds {\\n /** id региона-обёртки — на него вешается `aria-busy`. */\\n region: string;\\n /** id индикатора загрузки (`role=\\"status\\"`). */\\n status: string;\\n /** id сообщения об ошибке (`role=\\"alert\\"`). */\\n error: string;\\n}","summary":"Идентификаторы, которыми связываются регион, индикатор загрузки и сообщение об ошибке.","description":"Идентификаторы, которыми связываются регион, индикатор загрузки и сообщение об ошибке.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/AsyncBoundaryContext.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryLoading","kind":"function","signature":"export function AsyncBoundaryLoading({ children }: AsyncBoundarySlotProps)","summary":"AsyncBoundary.Loading — содержимое, видимое во время загрузки.","description":"AsyncBoundary.Loading — содержимое, видимое во время загрузки.\\n\\nУчитывает `delayMs` корня: при быстром ответе слот не показывается вовсе.\\nРазметку (`role=\\"status\\"`, `aria-live`) даёт ui-kit — CDK остаётся headless.","params":[],"example":"```tsx\\n<AsyncBoundary.Loading>\\n <p role=\\"status\\" aria-live=\\"polite\\">Загрузка данных…</p>\\n</AsyncBoundary.Loading>\\n```","examplesCount":1,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/AsyncBoundaryLoading.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryLoadingPropGetters","kind":"interface","signature":"export interface AsyncBoundaryLoadingPropGetters {\\n id: string;\\n role: \'status\';\\n \'aria-live\': \'polite\';\\n}","summary":"Пропсы индикатора загрузки.","description":"Пропсы индикатора загрузки. Политика объявления зафиксирована тестами a11y.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryRetry","kind":"const","signature":"export const AsyncBoundaryRetry","summary":"AsyncBoundary.Retry — кнопка повтора загрузки.","description":"AsyncBoundary.Retry — кнопка повтора загрузки.\\n\\nНе рендерится, если `onRetry` не передан в корень: контрол, который ничего не делает,\\nхуже отсутствующего — он читается скринридером и ловит фокус впустую.","params":[],"example":"Кнопка внутри слота ошибки\\n```tsx\\n<AsyncBoundary.Error>\\n<p role=\\"alert\\">Не удалось загрузить</p>\\n<AsyncBoundary.Retry>Повторить</AsyncBoundary.Retry>\\n</AsyncBoundary.Error>\\n```","examplesCount":2,"sourcePath":"src/components/async-boundary/AsyncBoundaryRetry.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryRetryProps","kind":"interface","signature":"export interface AsyncBoundaryRetryProps extends Omit<\\n ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Рендерить как дочерний элемент через Slot (props мержатся в children вместо `<button>`). */\\n asChild?: boolean;\\n}","summary":"Props кнопки `AsyncBoundary.Retry`.","description":"Props кнопки `AsyncBoundary.Retry`.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryRoot","kind":"const","signature":"const AsyncBoundaryRoot","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/AsyncBoundaryRoot.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryRootPropGetters","kind":"interface","signature":"export interface AsyncBoundaryRootPropGetters {\\n id: string;\\n \'data-status\': AsyncStatus;\\n \'data-refreshing\'?: true;\\n \'aria-busy\'?: true;\\n}","summary":"Пропсы региона-обёртки: `aria-busy` + data-атрибуты для CSS и e2e.","description":"Пропсы региона-обёртки: `aria-busy` + data-атрибуты для CSS и e2e.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundaryRootProps","kind":"interface","signature":"export interface AsyncBoundaryRootProps<T = unknown, E = unknown> {\\n // ── self-managed режим ────────────────────────────────────────────────────\\n /**\\n * Загрузчик. Получает `AbortSignal` — прокиньте его в `fetch`, чтобы отменённый\\n * запрос не висел в сети. Наличие этого пропа включает self-managed режим.\\n */\\n load?: (signal: AbortSignal) => Promise<T>;\\n /**\\n * Ключ перезапуска: при изменении стартует новая загрузка (обычно id записи).\\n * Сравнивается по `Object.is` — передавайте примитив, а не свежий объект.\\n */\\n loadKey?: unknown;\\n /**\\n * `false` → загрузка не стартует, состояние `idle`. Режим создания новой записи.\\n * @default true\\n */\\n enabled?: boolean;\\n /** Побочный эффект после успеха — например `form.patchValue(data)`. */\\n onSuccess?: (data: T) => void;\\n /** Побочный эффект после ошибки — логирование, тост. */\\n onError?: (error: E) => void;\\n /** Преобразование отказа промиса в отображаемую ошибку. По умолчанию — сообщение `Error`. */\\n toError?: (e: unknown) => E;\\n\\n // ── controlled режим ──────────────────────────────────────────────────────\\n /** Текущее состояние. Обязателен, когда `load` не передан. */\\n status?: AsyncStatus;\\n /** Ошибка, которую получит слот `AsyncBoundary.Error`. */\\n error?: E | null;\\n /**\\n * Идёт фоновое обновление поверх уже показанного контента.\\n * Контент остаётся видимым, `aria-busy` выставляется.\\n * @default false\\n */\\n refreshing?: boolean;\\n /** Повтор загрузки. Без него `AsyncBoundary.Retry` не рендерится, а `canRetry` — `false`. */\\n onRetry?: () => void;\\n\\n // ── общее ─────────────────────────────────────────────────────────────────\\n /**\\n * Не показывать слот загрузки первые N мс. Гасит вспышку спиннера, когда\\n * ответ приходит быстрее задержки. Не влияет на `status` — только на `isLoading`.\\n * @default 0\\n */\\n delayMs?: number;\\n /** Явный префикс для генерируемых id (иначе `useId`). */\\n id?: string;\\n /** Слоты `AsyncBoundary.*` и любой другой контент. */\\n children: ReactNode;\\n}","summary":"Props корневого провайдера `AsyncBoundary.Root`.","description":"Props корневого провайдера `AsyncBoundary.Root`.\\n\\nДва режима, взаимоисключающих:\\n\\n- **self-managed** — передан `load`: компонент грузит данные сам, ведёт статус,\\n отменяет запросы при смене `loadKey`/размонтировании, а `AsyncBoundary.Retry`\\n и `handle.reload()` перезапускают загрузку. Props `status` / `error` /\\n `refreshing` / `onRetry` в этом режиме игнорируются.\\n- **controlled** — `load` не передан: состояние приходит снаружи через `status`.\\n Нужен там, где загрузкой владеет кто-то другой — например behavior рендерера,\\n вызывающий `schema.node(\'boundary\').patchProps({ status })`.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncBoundarySlotProps","kind":"interface","signature":"export interface AsyncBoundarySlotProps {\\n /** Содержимое слота. */\\n children: ReactNode;\\n}","summary":"Props слотов, которые просто показывают/скрывают содержимое.","description":"Props слотов, которые просто показывают/скрывают содержимое.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncResourceAction","kind":"type","signature":"export type AsyncResourceAction<T, E> =\\n /** Загрузка отключена (`enabled: false`) — грузить нечего. */\\n | { kind: \'skip\' }\\n /** Запрос отправлен. */\\n | { kind: \'load-start\' }\\n /** Запрос успешно завершён. */\\n | { kind: \'load-success\'; data: T }\\n /** Запрос завершился ошибкой. */\\n | { kind: \'load-error\'; error: E }\\n /** Загрузка прервана вручную (`handle.abort()`). */\\n | { kind: \'abort\' };","summary":"Действия машины состояний.","description":"Действия машины состояний.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/async-resource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"asyncResourceReducer","kind":"function","signature":"export function asyncResourceReducer<T, E>(\\n state: AsyncResourceState<T, E>,\\n action: AsyncResourceAction<T, E>\\n): AsyncResourceState<T, E>","summary":"Редьюсер загрузки.","description":"Редьюсер загрузки.\\n\\nКлючевое правило перехода `load-start`: если данные уже есть, состояние остаётся\\n`ready` с поднятым `refreshing` (stale-while-revalidate) — иначе при каждом обновлении\\nконтент подменялся бы спиннером и пользователь терял бы позицию на экране.","params":[["state","- Текущее состояние."],["action","- Действие."]],"returns":"Новое состояние.","example":"Перезагрузка поверх данных не роняет экран в loading\\n```ts\\nlet s = initialAsyncResourceState<User, string>();\\ns = asyncResourceReducer(s, { kind: \'load-start\' }); // status: \'loading\'\\ns = asyncResourceReducer(s, { kind: \'load-success\', data: user }); // status: \'ready\'\\ns = asyncResourceReducer(s, { kind: \'load-start\' }); // \'ready\' + refreshing\\n```","examplesCount":2,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/async-resource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncResourceState","kind":"interface","signature":"export interface AsyncResourceState<T, E> {\\n /** Текущее состояние операции. */\\n status: AsyncStatus;\\n /** Последние успешно загруженные данные (сохраняются при ошибке и перезагрузке). */\\n data: T | undefined;\\n /** Ошибка последней попытки. */\\n error: E | null;\\n /** Идёт повторная загрузка поверх уже показанных данных. */\\n refreshing: boolean;\\n}","summary":"Снимок состояния загрузки.","description":"Снимок состояния загрузки.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/async-resource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"AsyncStatus","kind":"type","signature":"export type AsyncStatus = \'idle\' | \'loading\' | \'ready\' | \'error\';","summary":"Состояние асинхронной операции.","description":"Состояние асинхронной операции.\\n\\n- `\'idle\'` — загрузка не запускалась и не планируется (создание новой записи, id ещё не выбран).\\n Отдельное состояние нужно, чтобы «пустая форма» не выглядела как успешно загруженные данные.\\n- `\'loading\'` — запрос выполняется, данных ещё нет.\\n- `\'ready\'` — данные получены, показываем контент.\\n- `\'error\'` — запрос завершился ошибкой.\\n\\nФоновое обновление поверх уже показанных данных — это не отдельный статус, а флаг\\n`refreshing` при `status === \'ready\'` (stale-while-revalidate).","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/types.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"createMessageResolver","kind":"function","signature":"export function createMessageResolver(table: ValidationMessageTable): ValidationErrorResolver","summary":"Создаёт резолвер из таблицы кодов сообщений (точка i18n).","description":"Создаёт резолвер из таблицы кодов сообщений (точка i18n). Текст берётся по `error.code`\\nс подстановкой `error.params`; если кода нет в таблице — fallback на `error.message`, затем\\nна сам `error.code`. Позволяет валидаторам нести только `code`+`params`, а тексты (RU/EN/…)\\nдержать в таблице и менять без правки схемы валидации.","params":[["table","- Таблица `code → (params) => message`."]],"returns":"Резолвер {@link ValidationErrorResolver} для {@link ValidationMessagesProvider}.","example":"Таблица сообщений с подстановкой параметров\\n```ts\\nimport { createMessageResolver } from \'@reformer/cdk\';\\n\\nconst resolve = createMessageResolver({\\nrequired: () => \'Обязательное поле\',\\nminLength: (p) => `Минимум ${p?.minLength} символов`,\\n});\\n\\nresolve({ code: \'required\', message: \'старое\' }); // → \'Обязательное поле\'\\nresolve({ code: \'minLength\', message: \'\', params: { minLength: 3 } }); // → \'Минимум 3 символов\'\\nresolve({ code: \'pattern\', message: \'Неверный формат\' }); // → \'Неверный формат\' (fallback)\\n```","examplesCount":1,"related":["ValidationMessagesProvider"],"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk","usage":8},{"name":"defaultErrorResolver","kind":"const","signature":"export const defaultErrorResolver: ValidationErrorResolver","summary":"Дефолтный резолвер: отдаёт `error.message`, а если оно пустое — `error.code`.","description":"Дефолтный резолвер: отдаёт `error.message`, а если оно пустое — `error.code`. Применяется, когда\\nформа не обёрнута в {@link ValidationMessagesProvider}. Обеспечивает обратную совместимость:\\nпока валидаторы несут готовые тексты в `message`, отображение не меняется.","params":[],"example":"Прямое применение к ошибке\\n```ts\\nimport { defaultErrorResolver } from \'@reformer/cdk\';\\n\\ndefaultErrorResolver({ code: \'required\', message: \'Обязательно\' }); // → \'Обязательно\'\\ndefaultErrorResolver({ code: \'required\', message: \'\' }); // → \'required\'\\n```","examplesCount":1,"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk"},{"name":"defaultToError","kind":"function","signature":"export function defaultToError(e: unknown): string","summary":"Приведение неизвестного отказа промиса к человекочитаемой строке — дефолт для `toError`, когда консумент не задал своё преобразование.","description":"Приведение неизвестного отказа промиса к человекочитаемой строке —\\nдефолт для `toError`, когда консумент не задал своё преобразование.","params":[["e","- Значение, с которым отклонился промис."]],"returns":"Сообщение об ошибке.","example":"```ts\\ndefaultToError(new Error(\'Ошибка загрузки заявки\')); // \'Ошибка загрузки заявки\'\\ndefaultToError(\'boom\'); // \'boom\'\\ndefaultToError({}); // \'Неизвестная ошибка\'\\n```","examplesCount":1,"sourcePath":"src/components/async-boundary/async-resource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"defineSteps","kind":"function","signature":"export function defineSteps<Sel extends string, T extends object>(\\n model: FormModel<T>,\\n config: DefineStepsConfig<Sel, T>\\n): WizardStepsConfig<Sel>","summary":"Строит {@link FormWizardConfig} из правил, адресованных по `selector` шага.","description":"Строит {@link FormWizardConfig} из правил, адресованных по `selector` шага. `validateStep(n)`\\nрезолвит `n → selector → правила`; `validateAll` — все шаги + `extras`. Обе помечают `touched`\\nтолько провалидированные поля (`{ touch: true }`, §6). Результат — обычный конфиг, визард\\nпотребляет его без изменений.","params":[["model","- Модель формы."],["config","- {@link DefineStepsConfig}: `steps` (по `selector`) + опц. `extras`."]],"returns":"","example":"```ts\\nconst config = defineSteps<\'loan\' | \'applicant\' | \'confirm\', Root>(model, {\\n steps: { loan: step1, applicant: step2, confirm: null }, // confirm — без правил, ЯВНО\\n extras: crossFieldRules,\\n});\\n<FormWizard form={form} config={config}>…</FormWizard>\\n```","examplesCount":1,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/define-steps.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk","usage":2},{"name":"DefineStepsConfig","kind":"interface","signature":"export interface DefineStepsConfig<Sel extends string, T> {\\n /**\\n * Правила шагов. Ключ = `selector` шага (совпадает с id ноды шага в схеме); порядок ключей =\\n * порядок шагов в визарде. `null` — шаг без правил (объявляется ЯВНО, а не молча по умолчанию).\\n */\\n steps: Record<Sel, ValidationSchema<T> | null>;\\n /** Cross-field/warnings уровня всей формы — применяются только в `validateAll` (submit). */\\n extras?: ValidationSchema<T>;\\n /**\\n * Live-стратегия ВНУТРИ активного шага (`blur`/`change`/`afterFirstSubmit`) — для\\n * {@link useWizardStepValidation}. Не задана / `\'submit\'` → живой валидации внутри шага нет\\n * (остаётся только per-step gate на «Далее» + submit). Аддитивно: per-step gate/submit не меняются.\\n */\\n strategy?: ValidationStrategyKind;\\n /** Debounce (мс) для live-фаз внутришаговой стратегии (`change` / live-часть `afterFirstSubmit`). */\\n debounce?: number;\\n /** Режим live-фазы для `afterFirstSubmit`. Default `\'change\'`. */\\n liveAfterSubmit?: \'change\' | \'blur\';\\n}","summary":"Конфиг {@link defineSteps}: правила шагов по `selector` + form-level extras + live-стратегия шага.","description":"Конфиг {@link defineSteps}: правила шагов по `selector` + form-level extras + live-стратегия шага.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/define-steps.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FileError","kind":"type","signature":"export type FileError = ValidationError;","summary":"Ошибка отбора/загрузки файла.","description":"Ошибка отбора/загрузки файла. `code` разрешается в текст резолвером сообщений\\n(`useValidationErrorResolver`/`createMessageResolver`), поэтому тип — ровно\\n{@link ValidationError} из core: один резолвер обслуживает и валидацию, и отбор.\\n\\nКоды отбора: `\'fileType\' | \'maxFileSize\' | \'minFileSize\' | \'maxFiles\' |\\n\'maxTotalFileSize\' | \'fileExists\' | \'uploadFailed\' | \'uploadAborted\'`\\nили произвольный из кастомного `validate`. `message` по умолчанию — `\'invalid\'`\\n(как у core-валидаторов), в `params` — лимит/имя файла/фактическое значение.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":1},{"name":"fileItemKey","kind":"function","signature":"export function fileItemKey(file: File, seq: number): string","summary":"Стабильный уникальный ключ элемента.","description":"Стабильный уникальный ключ элемента. Уникальность даёт `seq` (сквозной счётчик\\nхука) — метаданные в ключе нужны только для отладки.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileRejection","kind":"interface","signature":"export interface FileRejection {\\n file: File;\\n /** Все нарушения сразу (файл может быть и не того типа, и слишком большим). */\\n errors: FileError[];\\n}","summary":"Файл, отклонённый при отборе.","description":"Файл, отклонённый при отборе. В значение поля не попадает — уходит в `onReject`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUpload","kind":"const","signature":"export const FileUpload","summary":"FileUpload — headless compound-компонент выбора и загрузки файлов.","description":"FileUpload — headless compound-компонент выбора и загрузки файлов.\\n\\n`<FileUpload>` — алиас `<FileUpload.Root>`; слоты доступны как свойства.\\nСм. документацию по частям в {@link FileUploadRoot}.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUpload.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":9},{"name":"FileUploadAction","kind":"type","signature":"export type FileUploadAction =\\n /** Итог отбора: принятые становятся `local`-элементами, отклонённые — в `rejections`. */\\n | { kind: \'add\'; accepted: File[]; keys: string[]; rejected: FileRejection[]; replace: boolean }\\n /** Удаление элемента. */\\n | { kind: \'remove\'; key: string }\\n /** Полная очистка. */\\n | { kind: \'clear\' }\\n /** Загрузка элемента стартовала (`local`/`error` → `uploading`). */\\n | { kind: \'upload-start\'; key: string }\\n /** Прогресс загрузки, проценты 0–100. */\\n | { kind: \'upload-progress\'; key: string; percent: number }\\n /** Загрузка завершена — элемент становится `uploaded` с дескриптором сервера. */\\n | { kind: \'upload-success\'; key: string; remote: RemoteFileRef }\\n /** Загрузка упала (или прервана — `code: \'uploadAborted\'`). */\\n | { kind: \'upload-error\'; key: string; error: FileError }\\n /** Повтор упавшей загрузки: `error` → `local` (очередь подхватит заново). */\\n | { kind: \'retry\'; key: string }\\n /** Синхронизация с внешним значением формы: список замещается пересобранным. */\\n | { kind: \'sync-items\'; items: FileUploadItem[] };","summary":"Действия редьюсера.","description":"Действия редьюсера.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadClearTrigger","kind":"const","signature":"export const FileUploadClearTrigger","summary":"FileUpload.ClearTrigger — кнопка полной очистки списка (все активные загрузки прерываются).","description":"FileUpload.ClearTrigger — кнопка полной очистки списка (все активные загрузки\\nпрерываются). Заблокирована при пустом списке.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadClearTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadClearTriggerProps","kind":"interface","signature":"export interface FileUploadClearTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\\n /** Рендерить собственный элемент вместо `<button>` (пропсы мержатся в него). */\\n asChild?: boolean;\\n}","summary":"Props `FileUpload.ClearTrigger`.","description":"Props `FileUpload.ClearTrigger`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadClearTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadComponent","kind":"type","signature":"export type FileUploadComponent = typeof FileUploadRoot & {\\n Root: typeof FileUploadRoot;\\n Trigger: typeof FileUploadTrigger;\\n Dropzone: typeof FileUploadDropzone;\\n ItemGroup: typeof FileUploadItemGroup;\\n Item: typeof FileUploadItem;\\n ItemPreview: typeof FileUploadItemPreview;\\n ItemName: typeof FileUploadItemName;\\n ItemSize: typeof FileUploadItemSize;\\n ItemProgress: typeof FileUploadItemProgress;\\n ItemDeleteTrigger: typeof FileUploadItemDeleteTrigger;\\n ItemRetryTrigger: typeof FileUploadItemRetryTrigger;\\n ClearTrigger: typeof FileUploadClearTrigger;\\n};","summary":"Тип compound-компонента `FileUpload` со слотами.","description":"Тип compound-компонента `FileUpload` со слотами.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUpload.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadContext","kind":"const","signature":"export const FileUploadContext","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadContextValue","kind":"type","signature":"export type FileUploadContextValue = UseFileUploadReturn;","summary":"Значение контекста `FileUpload` — целиком {@link UseFileUploadReturn}: слоты и кастомные части читают из него состояние, действия и prop-getters.","description":"Значение контекста `FileUpload` — целиком {@link UseFileUploadReturn}:\\nслоты и кастомные части читают из него состояние, действия и prop-getters.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadDropzone","kind":"const","signature":"export const FileUploadDropzone","summary":"FileUpload.Dropzone — зона drag-and-drop.","description":"FileUpload.Dropzone — зона drag-and-drop. Одновременно доступная кнопка:\\nклик и Enter/Space открывают пикер (drop никогда не единственный канал ввода).\\nСостояние подсветки — через `data-dragging`/`data-disabled`.\\n\\nКонсумент задаёт `aria-label` с перечислением ограничений\\n(«PNG или JPG, до 5 МБ, максимум 3 файла») — хук их текстом не формулирует.","params":[],"example":"```tsx\\n<FileUpload.Dropzone\\n aria-label=\\"Загрузка документов: PDF, до 10 МБ\\"\\n className=\\"dropzone data-[dragging]:highlight\\"\\n>\\n Перетащите файлы или нажмите\\n</FileUpload.Dropzone>\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadDropzone.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":3},{"name":"FileUploadDropzonePropGetters","kind":"interface","signature":"export interface FileUploadDropzonePropGetters {\\n id: string;\\n role: \'button\';\\n tabIndex: number;\\n \'aria-disabled\'?: true;\\n \'data-dragging\'?: true;\\n \'data-disabled\'?: true;\\n onClick: () => void;\\n onKeyDown: (e: KeyboardEvent) => void;\\n onFocus: (e: FocusEvent) => void;\\n onBlur: (e: FocusEvent) => void;\\n onDragEnter?: (e: DragEvent) => void;\\n onDragOver?: (e: DragEvent) => void;\\n onDragLeave?: (e: DragEvent) => void;\\n onDrop?: (e: DragEvent) => void;\\n onPaste?: (e: ClipboardEvent) => void;\\n}","summary":"Пропсы дроп-зоны: доступная кнопка (клик/Enter/Space → пикер) + drag/paste-каналы.","description":"Пропсы дроп-зоны: доступная кнопка (клик/Enter/Space → пикер) + drag/paste-каналы.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/useFileUpload.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadDropzoneProps","kind":"interface","signature":"export interface FileUploadDropzoneProps extends HTMLAttributes<HTMLElement> {\\n /** Рендерить собственный элемент вместо `<div>` (пропсы мержатся в него). */\\n asChild?: boolean;\\n}","summary":"Props `FileUpload.Dropzone`.","description":"Props `FileUpload.Dropzone`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadDropzone.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadHandle","kind":"interface","signature":"export interface FileUploadHandle {\\n /** Открыть системный пикер файлов. */\\n openFilePicker(): void;\\n /** Программно добавить файлы (пройдут тот же отбор, что выбор/drop). */\\n addFiles(files: File[]): void;\\n /** Удалить элемент списка (загрузка, если шла, прерывается). */\\n removeItem(key: string): void;\\n /** Очистить список целиком. */\\n clear(): void;\\n /** Повторить упавшую загрузку. */\\n retry(key: string): void;\\n /** Прервать загрузку элемента (или все, без `key`) — элемент остаётся с ошибкой `uploadAborted`. */\\n abort(key?: string): void;\\n /** Сфокусировать hidden input — для «подсветить невалидное поле». */\\n focus(): void;\\n}","summary":"Императивный handle `FileUpload.Root` (через ref), по образцу AsyncBoundaryHandle.","description":"Императивный handle `FileUpload.Root` (через ref), по образцу AsyncBoundaryHandle.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadIds","kind":"interface","signature":"export interface FileUploadIds {\\n root: string;\\n hiddenInput: string;\\n dropzone: string;\\n liveRegion: string;\\n}","summary":"Идентификаторы, которыми связываются зона, hidden input и live-регион статусов.","description":"Идентификаторы, которыми связываются зона, hidden input и live-регион статусов.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/useFileUpload.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItem","kind":"const","signature":"export const FileUploadItem","summary":"FileUpload.Item — строка файла (`<li role=\\"listitem\\" data-status=\\"…\\">`).","description":"FileUpload.Item — строка файла (`<li role=\\"listitem\\" data-status=\\"…\\">`).\\nПровайдит per-item контекст для `ItemName`/`ItemSize`/`ItemPreview`/`ItemProgress`/\\n`ItemDeleteTrigger`/`ItemRetryTrigger`.\\n\\n`data-status` (`local | uploading | uploaded | error`) — крючок для стилизации\\nи e2e-селекторов.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItem.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemContext","kind":"const","signature":"export const FileUploadItemContext","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemContextValue","kind":"interface","signature":"export interface FileUploadItemContextValue {\\n item: FileUploadItem;\\n}","summary":"Значение per-item контекста: элемент, который рендерит текущий `FileUpload.Item`.","description":"Значение per-item контекста: элемент, который рендерит текущий `FileUpload.Item`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemData","kind":"type","signature":"export type FileUploadItem =\\n | { key: string; status: \'local\'; file: File }\\n | { key: string; status: \'uploading\'; file: File; progress: number }\\n | { key: string; status: \'uploaded\'; file?: File; remote: RemoteFileRef }\\n | { key: string; status: \'error\'; file: File; error: FileError; progress?: number };","summary":"Элемент внутреннего списка файлов — дискриминированное объединение по `status`.","description":"Элемент внутреннего списка файлов — дискриминированное объединение по `status`.\\n\\n`key` — стабильный uid элемента (не индекс): по нему живут превью, abort-контроллеры\\nи React-ключи при переупорядочивании.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemDeleteTrigger","kind":"const","signature":"export const FileUploadItemDeleteTrigger","summary":"FileUpload.ItemDeleteTrigger — кнопка удаления файла из списка.","description":"FileUpload.ItemDeleteTrigger — кнопка удаления файла из списка. Активная загрузка\\nпри удалении прерывается. `aria-label` уже содержит имя файла\\n(«Удалить файл report.pdf»).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemDeleteTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemDeleteTriggerProps","kind":"interface","signature":"export interface FileUploadItemDeleteTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\\n /** Рендерить собственный элемент вместо `<button>` (пропсы мержатся в него). */\\n asChild?: boolean;\\n}","summary":"Props `FileUpload.ItemDeleteTrigger`.","description":"Props `FileUpload.ItemDeleteTrigger`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemDeleteTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemGroup","kind":"const","signature":"export const FileUploadItemGroup","summary":"FileUpload.ItemGroup — семантический список выбранных файлов (`<ul role=\\"list\\">`).","description":"FileUpload.ItemGroup — семантический список выбранных файлов (`<ul role=\\"list\\">`).\\nПустой список не рендерится вовсе.","params":[],"example":"```tsx\\n<FileUpload.ItemGroup>\\n {(item) => (\\n <FileUpload.Item key={item.key} item={item}>\\n <FileUpload.ItemName />\\n <FileUpload.ItemDeleteTrigger>×</FileUpload.ItemDeleteTrigger>\\n </FileUpload.Item>\\n )}\\n</FileUpload.ItemGroup>\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadItemGroup.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemGroupProps","kind":"interface","signature":"export interface FileUploadItemGroupProps extends Omit<\\n HTMLAttributes<HTMLUListElement>,\\n \'children\'\\n> {\\n /** Render prop: вызывается для каждого элемента списка (как `FormArray.List`). */\\n children: (item: FileUploadItem) => ReactNode;\\n}","summary":"Props `FileUpload.ItemGroup`.","description":"Props `FileUpload.ItemGroup`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemGroup.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemName","kind":"const","signature":"export const FileUploadItemName","summary":"FileUpload.ItemName — имя файла (`<span>`).","description":"FileUpload.ItemName — имя файла (`<span>`). Для `uploaded` без локального файла\\nберётся имя из дескриптора.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemName.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemNameProps","kind":"type","signature":"export type FileUploadItemNameProps = Omit<HTMLAttributes<HTMLSpanElement>, \'children\'>;","summary":"Props `FileUpload.ItemName`.","description":"Props `FileUpload.ItemName`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemName.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemPreview","kind":"const","signature":"export const FileUploadItemPreview","summary":"FileUpload.ItemPreview — превью файла.","description":"FileUpload.ItemPreview — превью файла. Для изображений рендерит `<img>` с managed\\nobject URL (создаётся лениво, revoke — на удалении элемента и unmount; сам слот\\nURL никогда не создаёт — этим владеет хук). Для остального — `children` (фолбэк).","params":[],"example":"Превью с иконкой-фолбэком\\n```tsx\\n<FileUpload.ItemPreview className=\\"size-10 rounded object-cover\\">\\n<FileIcon />\\n</FileUpload.ItemPreview>\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadItemPreview.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemPreviewProps","kind":"interface","signature":"export interface FileUploadItemPreviewProps extends Omit<\\n ImgHTMLAttributes<HTMLImageElement>,\\n \'src\' | \'children\'\\n> {\\n /** Фолбэк для не-изображений (иконка по типу файла и т.п.). */\\n children?: ReactNode;\\n}","summary":"Props `FileUpload.ItemPreview`.","description":"Props `FileUpload.ItemPreview`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemPreview.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemProgress","kind":"const","signature":"export const FileUploadItemProgress","summary":"FileUpload.ItemProgress — прогресс загрузки элемента.","description":"FileUpload.ItemProgress — прогресс загрузки элемента. Рендерится только в статусе\\n`uploading`: `role=\\"progressbar\\"` + `aria-valuenow` (целые проценты), `data-progress`\\nдля CSS.","params":[],"example":"Полоса прогресса\\n```tsx\\n<FileUpload.ItemProgress className=\\"h-1 bg-muted\\">\\n{(p) => <div style={{ width: `${p}%` }} className=\\"h-full bg-primary\\" />}\\n</FileUpload.ItemProgress>\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadItemProgress.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemProgressProps","kind":"interface","signature":"export interface FileUploadItemProgressProps extends Omit<\\n HTMLAttributes<HTMLDivElement>,\\n \'children\'\\n> {\\n /** Кастомный рендер (полоса, спиннер). По умолчанию — текст «NN%». */\\n children?: (progress: number) => ReactNode;\\n}","summary":"Props `FileUpload.ItemProgress`.","description":"Props `FileUpload.ItemProgress`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemProgress.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemProps","kind":"interface","signature":"export interface FileUploadItemProps extends LiHTMLAttributes<HTMLLIElement> {\\n /** Элемент списка из render prop `FileUpload.ItemGroup`. */\\n item: FileUploadItemType;\\n}","summary":"Props `FileUpload.Item`.","description":"Props `FileUpload.Item`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItem.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemRetryTrigger","kind":"const","signature":"export const FileUploadItemRetryTrigger","summary":"FileUpload.ItemRetryTrigger — кнопка повтора упавшей загрузки.","description":"FileUpload.ItemRetryTrigger — кнопка повтора упавшей загрузки. Рендерится только\\nв статусе `error` (в остальных повтор бессмыслен).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemRetryTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemRetryTriggerProps","kind":"interface","signature":"export interface FileUploadItemRetryTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\\n /** Рендерить собственный элемент вместо `<button>` (пропсы мержатся в него). */\\n asChild?: boolean;\\n}","summary":"Props `FileUpload.ItemRetryTrigger`.","description":"Props `FileUpload.ItemRetryTrigger`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemRetryTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemSize","kind":"const","signature":"export const FileUploadItemSize","summary":"FileUpload.ItemSize — человекочитаемый размер файла (`<span>`, «1.5 МБ»).","description":"FileUpload.ItemSize — человекочитаемый размер файла (`<span>`, «1.5 МБ»).\\nЕсли размер неизвестен (preloaded-дескриптор без `size`) — не рендерится.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemSize.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadItemSizeProps","kind":"type","signature":"export type FileUploadItemSizeProps = Omit<HTMLAttributes<HTMLSpanElement>, \'children\'>;","summary":"Props `FileUpload.ItemSize`.","description":"Props `FileUpload.ItemSize`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadItemSize.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"fileUploadReducer","kind":"function","signature":"export function fileUploadReducer(\\n state: FileUploadState,\\n action: FileUploadAction\\n): FileUploadState","summary":"Редьюсер списка файлов.","description":"Редьюсер списка файлов.\\n\\nПереходы статусов элемента: `local → uploading → uploaded | error`, `error → local`\\n(retry). Действия для несуществующего `key` или недопустимого исходного статуса —\\nno-op (возвращается прежний state): загрузка может завершиться после удаления\\nэлемента, и это не должно ронять список.","params":[["state","- Текущее состояние."],["action","- Действие."]],"returns":"Новое состояние.","examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadRoot","kind":"const","signature":"export const FileUploadRoot","summary":"FileUpload.Root — провайдер контекста и владелец поведения выбора/загрузки файлов.","description":"FileUpload.Root — провайдер контекста и владелец поведения выбора/загрузки файлов.\\n\\nСам рендерит только служебные узлы: hidden `<input type=\\"file\\">` (настоящий input —\\nоснова доступности: `label`/click/`focus()` работают нативно) и visually-hidden\\n`aria-live`-регион статусов («файл добавлен», «загрузка завершена», ошибки).\\nВсю видимую разметку дают слоты (`Trigger`/`Dropzone`/`ItemGroup`/…) и обёртки\\nиз `@reformer/ui-kit`.\\n\\nРежимы значения поля:\\n- **deferred** (без `uploader`) — значение `File[]`, сеть — забота консумента при submit;\\n- **immediate** (задан `uploader`) — файлы уходят на сервер при выборе, значение —\\n сериализуемые дескрипторы {@link RemoteFileRef} (только успешно загруженные).","params":[],"example":"Deferred: кнопка + список\\n```tsx\\n<FileUpload.Root value={value} onChange={setValue} accept=\\".pdf\\" multiple maxFiles={3}>\\n<FileUpload.Trigger>Выбрать файлы</FileUpload.Trigger>\\n<FileUpload.ItemGroup>\\n{(item) => (\\n<FileUpload.Item key={item.key} item={item}>\\n<FileUpload.ItemName />\\n<FileUpload.ItemSize />\\n<FileUpload.ItemDeleteTrigger>×</FileUpload.ItemDeleteTrigger>\\n</FileUpload.Item>\\n)}\\n</FileUpload.ItemGroup>\\n</FileUpload.Root>\\n```","examplesCount":3,"sourcePath":"src/components/file-upload/FileUploadRoot.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadRootPropGetters","kind":"interface","signature":"export interface FileUploadRootPropGetters {\\n id: string;\\n \'data-dragging\'?: true;\\n \'data-disabled\'?: true;\\n}","summary":"Пропсы контейнера: data-атрибуты для CSS и e2e.","description":"Пропсы контейнера: data-атрибуты для CSS и e2e.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/useFileUpload.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadRootProps","kind":"interface","signature":"export interface FileUploadRootProps extends UseFileUploadOptions {\\n children?: ReactNode;\\n}","summary":"Props `FileUpload.Root`: опции хука + children.","description":"Props `FileUpload.Root`: опции хука + children.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadRoot.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadState","kind":"interface","signature":"export interface FileUploadState {\\n /** Текущий список (принятые файлы во всех статусах). */\\n items: FileUploadItem[];\\n /** Отклонённые ПОСЛЕДНИМ отбором (сбрасываются следующим отбором и clear). */\\n rejections: FileRejection[];\\n}","summary":"Снимок состояния списка файлов.","description":"Снимок состояния списка файлов.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadTrigger","kind":"const","signature":"export const FileUploadTrigger","summary":"FileUpload.Trigger — кнопка «выбрать файлы»: открывает системный пикер.","description":"FileUpload.Trigger — кнопка «выбрать файлы»: открывает системный пикер.","params":[],"example":"Со своей кнопкой из ui-kit\\n```tsx\\n<FileUpload.Trigger asChild>\\n<Button variant=\\"outline\\">Выбрать файлы</Button>\\n</FileUpload.Trigger>\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadTriggerProps","kind":"interface","signature":"export interface FileUploadTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\\n /** Рендерить собственный элемент вместо `<button>` (пропсы мержатся в него). */\\n asChild?: boolean;\\n}","summary":"Props `FileUpload.Trigger`.","description":"Props `FileUpload.Trigger`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadTrigger.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FileUploadUploader","kind":"type","signature":"export type FileUploadUploader = (\\n file: File,\\n ctx: { onProgress: (percent: number) => void; signal: AbortSignal }\\n) => Promise<RemoteFileRef>;","summary":"Контракт загрузчика.","description":"Контракт загрузчика. Дефолтной реализации нет — только инжекция консумента\\n(XHR с `xhr.upload.onprogress`, tus, presigned S3 — что угодно, возвращающее дескриптор).\\n\\nРеализация обязана уважать `signal` (прервать запрос) и может репортить\\nпрогресс в процентах через `onProgress`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":2},{"name":"FileUploadValue","kind":"type","signature":"export type FileUploadValue = File[] | RemoteFileRef[] | null;","summary":"Значение поля формы: `File[]` (без uploader) либо `RemoteFileRef[]` (с uploader, только успешно загруженные).","description":"Значение поля формы: `File[]` (без uploader) либо `RemoteFileRef[]` (с uploader,\\nтолько успешно загруженные). Пустой список эмитится как `null`, чтобы `required()`\\nработал без изменений.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":7},{"name":"FormArray","kind":"const","signature":"export const FormArray","summary":"FormArray - Headless compound component for managing form arrays Provides complete flexibility for building array UI while handling all the form array state and actions internally.","description":"FormArray - Headless compound component for managing form arrays\\n\\nProvides complete flexibility for building array UI while handling\\nall the form array state and actions internally.\\n\\n## Features\\n- **Headless** - complete freedom in building UI\\n- **Compound Components** - declarative API via nested components\\n- **External Control** - control from outside via ref (useImperativeHandle)\\n- **Type Safe** - full TypeScript support\\n\\n## Sub-components\\n- `FormArray.Root` - context provider, accepts ref for external control\\n- `FormArray.List` - iterates over array items\\n- `FormArray.AddButton` - button to add item\\n- `FormArray.RemoveButton` - button to remove item (inside List)\\n- `FormArray.Empty` - content for empty state\\n- `FormArray.Count` - display item count\\n- `FormArray.ItemIndex` - display item index (inside List)\\n- `FormArray.Error` - display array-level validation errors (e.g. minItems)\\n\\n## FormArrayHandle API (ref)\\n- `add(value?)` - add item to the end\\n- `insert(index, value?)` - insert item at position\\n- `removeAt(index)` - remove item by index\\n- `move(from, to)` - reorder item (state preserved)\\n- `swap(a, b)` - swap two items (state preserved)\\n- `clear()` - clear array\\n- `at(index)` - get item control by index\\n- `length` - current item count\\n- `isEmpty` - empty array flag","params":[],"example":"Basic usage\\n```tsx\\n<FormArray.Root control={form.properties}>\\n<h3>Properties (<FormArray.Count />)</h3>\\n\\n<FormArray.Empty>\\n<p className=\\"text-gray-500\\">No properties added</p>\\n</FormArray.Empty>\\n\\n<FormArray.List className=\\"space-y-4\\">\\n{({ control }) => (\\n<div className=\\"p-4 border rounded\\">\\n<div className=\\"flex justify-between mb-2\\">\\n <h4>Property #<FormArray.ItemIndex /></h4>\\n <FormArray.RemoveButton className=\\"text-red-500\\">\\n Remove\\n </FormArray.RemoveButton>\\n</div>\\n<PropertyForm control={control} />\\n</div>\\n)}\\n</FormArray.List>\\n\\n<FormArray.AddButton className=\\"mt-4 btn-primary\\">\\n+ Add Property\\n</FormArray.AddButton>\\n</FormArray.Root>\\n```","examplesCount":3,"topics":["overview","form-array","form-field","recipes","troubleshooting"],"sourcePath":"src/components/form-array/FormArray.tsx","entries":[".","./form-array"],"package":"@reformer/cdk","usage":10},{"name":"FormArrayAddButton","kind":"const","signature":"export const FormArrayAddButton","summary":"`FormArray.AddButton` — кнопка добавления нового элемента в массив.","description":"`FormArray.AddButton` — кнопка добавления нового элемента в массив.\\n\\nРендерит `<button type=\\"button\\">` (или произвольный элемент через `asChild`),\\nпо клику вызывает `add(initialValue)` из контекста {@link FormArrayContext},\\nто есть `ArrayNode.push`. Должна находиться внутри `FormArray.Root` (или\\nэквивалентного провайдера), иначе `useFormArrayContext` бросит исключение.\\n\\nGeneric `T` — тип элемента массива. По умолчанию `Record<string, unknown>` (широкий).\\nПередавайте его явно, если нужна type-safe проверка `initialValue`:\\n`<FormArray.AddButton<PropertyItem> initialValue={...}>`.","params":[],"example":"Внутри compound-разметки FormArray\\n```tsx\\n<FormArray.Root control={form.properties}>\\n<FormArray.List>\\n{({ control }) => <PropertyForm control={control} />}\\n</FormArray.List>\\n\\n<FormArray.AddButton className=\\"btn-primary\\">\\n+ Добавить объект\\n</FormArray.AddButton>\\n</FormArray.Root>\\n```","examplesCount":3,"sourcePath":"src/components/form-array/FormArrayAddButton.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayAddButtonProps","kind":"interface","signature":"export interface FormArrayAddButtonProps<T extends object = Record<string, unknown>> extends Omit<\\n React.ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Начальное значение нового элемента (передаётся в `add()` → `ArrayNode.push`) */\\n initialValue?: Partial<T>;\\n /** Рендерить как дочерний элемент через Slot (props мержатся в children вместо `<button>`) */\\n asChild?: boolean;\\n}","summary":"Props for FormArray.AddButton component Generic `T` — тип элемента массива.","description":"Props for FormArray.AddButton component\\n\\nGeneric `T` — тип элемента массива. По умолчанию `Record<string, unknown>` (широкий) —\\nдля совместимости. Для type-safe initialValue передавайте generic явно\\n(`<FormArray.AddButton<PropertyItem> ...>`) либо проксируйте через\\n`FormArraySection<T>` из `@reformer/ui-kit`.","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayContext","kind":"const","signature":"export const FormArrayContext","summary":"React context, который снабжает дочерние компоненты `FormArray` (List, AddButton, …) текущим `ArrayNode` и хелперами.","description":"React context, который снабжает дочерние компоненты `FormArray` (List, AddButton, …)\\nтекущим `ArrayNode` и хелперами. Создаётся `FormArray.Root`. Читать через {@link useFormArrayContext}.","params":[],"example":"```tsx\\nimport { FormArrayContext } from \'@reformer/cdk/form-array\';\\n\\nfunction MyConsumer() {\\n const ctx = useContext(FormArrayContext);\\n return <span>items: {ctx?.items.length}</span>;\\n}\\n```","examplesCount":1,"topics":["form-array","recipes"],"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayContextValue","kind":"interface","signature":"export interface FormArrayContextValue<T extends object = Record<string, unknown>> {\\n /** Массив элементов с контролами и действиями */\\n items: FormArrayItem<T>[];\\n /** Текущая длина массива */\\n length: number;\\n /** Пустой ли массив */\\n isEmpty: boolean;\\n /** Добавить новый элемент в конец */\\n add: (value?: Partial<T>) => void;\\n /** Удалить все элементы */\\n clear: () => void;\\n /** Вставить элемент на указанную позицию */\\n insert: (index: number, value?: Partial<T>) => void;\\n /** Удалить элемент по индексу (симметрично insert-by-index) */\\n removeAt: (index: number) => void;\\n /** Переместить элемент (реордер, состояние сохраняется) */\\n move: (from: number, to: number) => void;\\n /** Поменять местами два элемента (реордер, состояние сохраняется) */\\n swap: (a: number, b: number) => void;\\n /** Получить контрол элемента по индексу */\\n at: (index: number) => FormProxy<T> | undefined;\\n /** Ошибки уровня массива (например `minItems` / «At least one phone required») */\\n errors: ValidationError[];\\n /** Валиден ли массив (и все его элементы) */\\n valid: boolean;\\n /** Невалиден ли массив (есть ошибки массива или любого элемента) */\\n invalid: boolean;\\n /**\\n * Оригинальный узел массива. Типизирован как `ArrayNode<T>` (не union с `ModelArrayNode`),\\n * чтобы существующие консументы контекста, передающие `control` в `useFormControl` (AddButton/\\n * RemoveButton), продолжали типизироваться под array-перегрузку. M1 `ModelArrayNode` совместим\\n * структурно и корректно работает в рантайме (контекст `<any>`-стёрт при создании в FormArray.Root).\\n */\\n control: ArrayNode<T>;\\n}","summary":"Контекст уровня массива","description":"Контекст уровня массива","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayControl","kind":"type","signature":"export type FormArrayControl<T extends object> = ArrayNode<T> | ModelArrayNode<T>;","summary":"Узел массива, принимаемый CDK-компонентами FormArray.","description":"Узел массива, принимаемый CDK-компонентами FormArray.\\n\\nLegacy {@link ArrayNode} (владеет элементами сам) ИЛИ M1 {@link ModelArrayNode} (делегирует\\nмассиву модели). Оба структурно реализуют используемый CDK контракт\\n(`push`/`insert`/`removeAt`/`move`/`swap`/`clear`/`at`/`map`/`length`/`value`/`errors`/…), но\\nModelArrayNode расширяет `FormNode<T[]>`, а не `ArrayNode`, поэтому нужен явный union — иначе\\nконсументы M1 (у которых `form.<field>` материализуется как ModelArrayNode) вынуждены кастовать.","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":["./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayCount","kind":"function","signature":"export function FormArrayCount({ render }: FormArrayCountProps)","summary":"FormArray.Count - Displays the number of items in the array","description":"FormArray.Count - Displays the number of items in the array","params":[],"example":"Basic usage\\n```tsx\\n<h3>Items (<FormArray.Count />)</h3>\\n```","examplesCount":2,"sourcePath":"src/components/form-array/FormArrayCount.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayCountProps","kind":"interface","signature":"export interface FormArrayCountProps {\\n /** Custom render function for the count */\\n render?: (count: number) => ReactNode;\\n}","summary":"Props for FormArray.Count component","description":"Props for FormArray.Count component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayEmpty","kind":"function","signature":"export function FormArrayEmpty({ children }: FormArrayEmptyProps)","summary":"FormArray.Empty - Renders children only when array is empty","description":"FormArray.Empty - Renders children only when array is empty","params":[],"example":"Basic usage\\n```tsx\\n<FormArray.Empty>\\n<p className=\\"text-gray-500\\">No items added yet</p>\\n</FormArray.Empty>\\n```","examplesCount":2,"sourcePath":"src/components/form-array/FormArrayEmpty.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayEmptyProps","kind":"interface","signature":"export interface FormArrayEmptyProps {\\n /** Content to show when array is empty */\\n children: ReactNode;\\n}","summary":"Props for FormArray.Empty component","description":"Props for FormArray.Empty component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayError","kind":"const","signature":"export const FormArrayError","summary":"FormArray.Error — рендерит ошибки уровня массива (`control.errors`).","description":"FormArray.Error — рендерит ошибки уровня массива (`control.errors`).\\n\\nПаритет с `FormField.Error`, но для узла массива: показывает array-level ошибки вроде `minItems`\\n/ «At least one phone required», которые ядро выставляет через `ArrayNode.setErrors` и агрегирует\\nв сигнале `errors`. Ничего не рендерит, когда ошибок нет. Читает контекст `FormArray.Root`, поэтому\\nконсументу больше не нужно обходить CDK через `useFormControl(control)` ради валидации массива.","params":[],"example":"Единственная ошибка (по умолчанию)\\n```tsx\\n<FormArray.Root control={form.phones}>\\n<FormArray.List>{({ control }) => <PhoneForm control={control} />}</FormArray.List>\\n<FormArray.Error className=\\"text-xs text-red-600\\" />\\n</FormArray.Root>\\n```","examplesCount":3,"sourcePath":"src/components/form-array/FormArrayError.tsx","entries":["./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayErrorProps","kind":"interface","signature":"export interface FormArrayErrorProps extends Omit<\\n React.HTMLAttributes<HTMLParagraphElement>,\\n \'role\'\\n> {\\n /** Рендерить как дочерний элемент через Slot (props мержатся в children). */\\n asChild?: boolean;\\n /**\\n * Рендерить все ошибки массива вместо только первой.\\n * @default false\\n */\\n multi?: boolean;\\n /** Кастомный рендер на каждую ошибку. Когда задан — `multi` подразумевается. */\\n render?: (error: ValidationError, index: number) => ReactNode;\\n /** Переопределить содержимое (по умолчанию `errors[0].message` через резолвер). */\\n children?: ReactNode;\\n}","summary":"Props for FormArray.Error component — рендерит ошибки уровня массива (например `minItems` / «At least one phone required») из `control.errors`.","description":"Props for FormArray.Error component — рендерит ошибки уровня массива\\n(например `minItems` / «At least one phone required») из `control.errors`.\\n\\nПаритет с `FormField.Error`: `multi` рендерит все ошибки, `render` — кастомный рендер на ошибку,\\n`children` переопределяет содержимое. Ничего не рендерит, когда ошибок нет.","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":["./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayHandle","kind":"interface","signature":"export interface FormArrayHandle<T extends object> {\\n /** Add a new item to the end of the array */\\n add: (value?: Partial<T>) => void;\\n /** Remove all items from the array */\\n clear: () => void;\\n /** Insert a new item at a specific index */\\n insert: (index: number, value?: Partial<T>) => void;\\n /** Remove item at specific index */\\n removeAt: (index: number) => void;\\n /** Move an item from one index to another (reorder, state preserved) */\\n move: (from: number, to: number) => void;\\n /** Swap two items by index (reorder, state preserved) */\\n swap: (a: number, b: number) => void;\\n /** Current number of items */\\n length: number;\\n /** Whether the array is empty */\\n isEmpty: boolean;\\n /** Get item control at specific index */\\n at: (index: number) => FormProxy<T> | undefined;\\n}","summary":"Handle exposed via ref for external control of {@link FormArray}.","description":"Handle exposed via ref for external control of {@link FormArray}.\\n\\nИмперо-API для случаев, когда триггер находится вне дерева `FormArray.Root`\\n(тулбар страницы, диалог подтверждения, async-эффект). Получают через\\n`useRef<FormArrayHandle<T>>(null)` и передают в `<FormArray.Root ref={...}>`.\\n\\nСвойства `length` / `isEmpty` — снимок на момент рендера. Реактивную длину\\nдля условного UI снаружи берите через `useFormControl(arrayNode).length`.","params":[],"example":"Тулбар «Добавить / Очистить» поверх массива\\n```tsx\\nimport { useRef } from \'react\';\\nimport { FormArray, type FormArrayHandle } from \'@reformer/cdk/form-array\';\\n\\nfunction PropertiesEditor({ form }: Props) {\\nconst arrayRef = useRef<FormArrayHandle<Property>>(null);\\n\\nreturn (\\n<>\\n<div className=\\"toolbar\\">\\n<button onClick={() => arrayRef.current?.add({ type: \'apartment\' })}>\\n + Квартира\\n</button>\\n<button onClick={() => arrayRef.current?.add({ type: \'house\' })}>\\n + Дом\\n</button>\\n<button onClick={() => confirm(\'Удалить всё?\') && arrayRef.current?.clear()}>\\n Очистить\\n</button>\\n</div>\\n<FormArray.Root ref={arrayRef} control={form.properties}>\\n<FormArray.List>{({ control }) => <PropertyForm control={control} />}</FormArray.List>\\n</FormArray.Root>\\n</>\\n);\\n}\\n```","examplesCount":2,"topics":["form-array","recipes","troubleshooting"],"sourcePath":"src/components/form-array/FormArray.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItem","kind":"interface","signature":"export interface FormArrayItem<T extends object> {\\n /** Контрол для данного элемента */\\n control: FormProxy<T>;\\n /** Индекс элемента (0-based) */\\n index: number;\\n /** Уникальный идентификатор для React key */\\n id: string | number;\\n /** Удалить этот элемент из массива */\\n remove: () => void;\\n /** Переместить элемент на одну позицию вверх (no-op если он первый) */\\n moveUp: () => void;\\n /** Переместить элемент на одну позицию вниз (no-op если он последний) */\\n moveDown: () => void;\\n /** Можно ли переместить вверх (index > 0) */\\n canMoveUp: boolean;\\n /** Можно ли переместить вниз (index < length - 1) */\\n canMoveDown: boolean;\\n}","summary":"Представляет элемент массива с контролом, индексом и действиями (включая хелперы reorder, чтобы консументы сырого `useFormArray`/контекста получали тот же набор, что и `FormArray.List`).","description":"Представляет элемент массива с контролом, индексом и действиями (включая хелперы reorder,\\nчтобы консументы сырого `useFormArray`/контекста получали тот же набор, что и `FormArray.List`).","params":[],"examplesCount":0,"topics":["form-array"],"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItemContext","kind":"const","signature":"export const FormArrayItemContext","summary":"React context, видимый внутри `FormArray.List` для одного элемента массива.","description":"React context, видимый внутри `FormArray.List` для одного элемента массива.\\nСодержит `control`, `index`, `id`, `remove()` и хелперы реордера\\n(`moveUp`/`moveDown`, `canMoveUp`/`canMoveDown`). Читать через {@link useFormArrayItemContext}.","params":[],"example":"```tsx\\nimport { FormArrayItemContext } from \'@reformer/cdk/form-array\';\\n\\nfunction CurrentIndex() {\\n const item = useContext(FormArrayItemContext);\\n return <small>#{item?.index}</small>;\\n}\\n```","examplesCount":1,"topics":["troubleshooting"],"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItemContextValue","kind":"interface","signature":"export interface FormArrayItemContextValue<T extends object = Record<string, unknown>> {\\n /** Контрол для данного элемента */\\n control: FormProxy<T>;\\n /** Индекс элемента (0-based) */\\n index: number;\\n /** Уникальный идентификатор для React key */\\n id: string | number;\\n /** Удалить этот элемент из массива */\\n remove: () => void;\\n /** Переместить элемент на одну позицию вверх (no-op если он первый) */\\n moveUp: () => void;\\n /** Переместить элемент на одну позицию вниз (no-op если он последний) */\\n moveDown: () => void;\\n /** Можно ли переместить вверх (index > 0) */\\n canMoveUp: boolean;\\n /** Можно ли переместить вниз (index < length - 1) */\\n canMoveDown: boolean;\\n}","summary":"Контекст уровня элемента массива","description":"Контекст уровня элемента массива","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItemIndex","kind":"function","signature":"export function FormArrayItemIndex({ render }: FormArrayItemIndexProps)","summary":"`FormArray.ItemIndex` — выводит номер текущего элемента (должен находиться внутри `FormArray.List` / item-шаблона; читает индекс из {@link FormArrayItemContext}).","description":"`FormArray.ItemIndex` — выводит номер текущего элемента (должен находиться\\nвнутри `FormArray.List` / item-шаблона; читает индекс из\\n{@link FormArrayItemContext}).\\n\\nПо умолчанию показывает 1-based номер (`index + 1`) — так удобнее для UI.\\nПроп `render` получает исходный 0-based `index`, поэтому позволяет вывести\\nлюбую форму (в т.ч. 0-based).","params":[],"example":"По умолчанию — 1-based (рендерит 1, 2, 3, …)\\n```tsx\\n<FormArray.List>\\n{() => (\\n<h4>Объект #<FormArray.ItemIndex /></h4>\\n)}\\n</FormArray.List>\\n```","examplesCount":3,"sourcePath":"src/components/form-array/FormArrayItemIndex.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItemIndexProps","kind":"interface","signature":"export interface FormArrayItemIndexProps {\\n /** Custom render function for the index (receives 0-based index) */\\n render?: (index: number) => ReactNode;\\n}","summary":"Props for FormArray.ItemIndex component","description":"Props for FormArray.ItemIndex component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayItemRenderProps","kind":"interface","signature":"export interface FormArrayItemRenderProps<T extends object> {\\n /** The form control for this item */\\n control: FormProxy<T>;\\n /** Zero-based index of the item */\\n index: number;\\n /** Unique identifier for React key */\\n id: string | number;\\n /** Remove this item from the array */\\n remove: () => void;\\n /** Move this item one position up (no-op when first) */\\n moveUp: () => void;\\n /** Move this item one position down (no-op when last) */\\n moveDown: () => void;\\n /** Whether this item can move up (index > 0) */\\n canMoveUp: boolean;\\n /** Whether this item can move down (index < length - 1) */\\n canMoveDown: boolean;\\n}","summary":"Props passed to the render function in FormArray.List","description":"Props passed to the render function in FormArray.List","params":[],"examplesCount":0,"topics":["form-array"],"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayList","kind":"function","signature":"export function FormArrayList<T extends object>({\\n children,\\n className,\\n as = \'div\',\\n}: FormArrayListProps<T>)","summary":"FormArray.List - Iterates over array items and provides item context","description":"FormArray.List - Iterates over array items and provides item context","params":[],"example":"Basic usage\\n```tsx\\n<FormArray.List>\\n{({ control, index, remove }) => (\\n<div>\\n<span>Item #{index + 1}</span>\\n<button onClick={remove}>Remove</button>\\n<ItemForm control={control} />\\n</div>\\n)}\\n</FormArray.List>\\n```","examplesCount":2,"sourcePath":"src/components/form-array/FormArrayList.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayListProps","kind":"interface","signature":"export interface FormArrayListProps<T extends object> {\\n /** Render function for each item */\\n children: (item: FormArrayItemRenderProps<T>) => ReactNode;\\n /** Optional className for the list container */\\n className?: string;\\n /** Optional element type for the container (default: \'div\') */\\n as?: ElementType;\\n}","summary":"Props for FormArray.List component","description":"Props for FormArray.List component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayRemoveButton","kind":"const","signature":"export const FormArrayRemoveButton","summary":"FormArray.RemoveButton - Button to remove current item (must be inside FormArray.List)","description":"FormArray.RemoveButton - Button to remove current item (must be inside FormArray.List)","params":[],"example":"Basic usage\\n```tsx\\n<FormArray.List>\\n{({ control }) => (\\n<div>\\n<ItemForm control={control} />\\n<FormArray.RemoveButton className=\\"text-red-500\\">\\nRemove\\n</FormArray.RemoveButton>\\n</div>\\n)}\\n</FormArray.List>\\n```","examplesCount":2,"sourcePath":"src/components/form-array/FormArrayRemoveButton.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayRemoveButtonProps","kind":"interface","signature":"export interface FormArrayRemoveButtonProps extends Omit<\\n React.ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Рендерить как дочерний элемент через Slot (props мержатся в children вместо `<button>`) */\\n asChild?: boolean;\\n}","summary":"Props for FormArray.RemoveButton component","description":"Props for FormArray.RemoveButton component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"FormArrayRootProps","kind":"interface","signature":"export interface FormArrayRootProps<T extends object> {\\n /** The array control from the form — legacy ArrayNode или M1 ModelArrayNode */\\n control: FormArrayControl<T>;\\n /** Child components */\\n children: ReactNode;\\n}","summary":"Props for FormArray.Root component","description":"Props for FormArray.Root component","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/types.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"formatFileSize","kind":"function","signature":"export function formatFileSize(bytes: number): string","summary":"Человекочитаемый размер файла: `1024`-base, одна цифра после точки, без хвоста `.0`.","description":"Человекочитаемый размер файла: `1024`-base, одна цифра после точки, без хвоста `.0`.","params":[],"example":"```ts\\nformatFileSize(512); // \'512 Б\'\\nformatFileSize(1536); // \'1.5 КБ\'\\nformatFileSize(5_242_880); // \'5 МБ\'\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"FormField","kind":"const","signature":"export const FormField","summary":"FormField - Headless compound component for accessible form field anatomy.","description":"FormField - Headless compound component for accessible form field anatomy.\\n\\nProvides complete freedom in building field UI while handling all accessible\\nID wiring (htmlFor, aria-labelledby, aria-describedby, aria-errormessage)\\nand field state management internally.\\n\\n## Features\\n- **Headless** — complete freedom in building UI, no styles imposed\\n- **Compound Components** — declarative API via nested components\\n- **Accessible by default** — all ARIA relationships wired automatically\\n- **Type Safe** — full TypeScript support with generics\\n\\n## Sub-components\\n- `FormField.Root` — context provider, accepts `control` and optional `id`\\n- `FormField.Label` — `<label>` with automatic `htmlFor` and required indicator\\n- `FormField.Control` — auto-renders `control.component` or wraps custom children\\n- `FormField.Error` — error message with `role=\\"alert\\"`, supports multi-error\\n- `FormField.Description` — helper text with stable `id` for `aria-describedby`","params":[],"example":"Minimal (auto-renders everything from field config)\\n```tsx\\n<FormField.Root control={control.email}>\\n<FormField.Label />\\n<FormField.Control />\\n<FormField.Error />\\n</FormField.Root>\\n```","examplesCount":4,"topics":["overview","form-array","form-field","recipes","troubleshooting"],"sourcePath":"src/components/form-field/FormField.tsx","entries":[".","./form-field"],"package":"@reformer/cdk","usage":156},{"name":"FormFieldContext","kind":"const","signature":"export const FormFieldContext","summary":"React context, который снабжает дочерние компоненты `FormField` (Label, Error, Hint, Control) текущим контролом.","description":"React context, который снабжает дочерние компоненты `FormField` (Label, Error,\\nHint, Control) текущим контролом. Создаётся `FormField.Root`. Читать через\\n{@link useFormFieldContext}.","params":[],"example":"```tsx\\nimport { FormFieldContext } from \'@reformer/cdk/form-field\';\\n\\nfunction CurrentValue() {\\n const ctx = useContext(FormFieldContext);\\n return <pre>{JSON.stringify(ctx?.control.value)}</pre>;\\n}\\n```","examplesCount":1,"sourcePath":"src/components/form-field/FormFieldContext.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldContextValue","kind":"interface","signature":"export interface FormFieldContextValue<T extends FormValue = FormValue> {\\n // ─── Field state ──────────────────────────────────────────────────────────\\n value: T;\\n errors: ValidationError[];\\n pending: boolean;\\n disabled: boolean;\\n valid: boolean;\\n invalid: boolean;\\n touched: boolean;\\n shouldShowError: boolean;\\n /** First error message, only set when shouldShowError is true */\\n error: string | undefined;\\n // ─── Derived from componentProps ──────────────────────────────────────────\\n label: string | undefined;\\n required: boolean;\\n /** Full componentProps bag */\\n componentProps: Record<string, unknown>;\\n // ─── The control itself ───────────────────────────────────────────────────\\n control: FieldNode<T>;\\n // ─── Accessible IDs ───────────────────────────────────────────────────────\\n ids: FormFieldIds;\\n /** Whether a FormField.Description is present (drives aria-describedby on Control) */\\n hasDescription: boolean;\\n}","summary":"Context value provided by FormField.Root","description":"Context value provided by FormField.Root","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldControl","kind":"const","signature":"export const FormFieldControl","summary":"FormField.Control - Renders the interactive form control.","description":"FormField.Control - Renders the interactive form control.\\n\\n**Auto-render mode** (default): renders `control.component` with all necessary\\nprops pre-wired: `value`, `onChange`, `onBlur`, `disabled`, `aria-*` attributes,\\nand all `componentProps` from the field config.\\n\\n**Custom children mode** (`asChild` or `children`): merges accessible props\\ninto the provided child element via Slot, letting you use any custom component.","params":[],"example":"Auto-render (renders control.component)\\n```tsx\\n<FormField.Root control={control.email}>\\n<FormField.Label />\\n<FormField.Control />\\n</FormField.Root>\\n```","examplesCount":3,"sourcePath":"src/components/form-field/FormFieldControl.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldControlProps","kind":"interface","signature":"export interface FormFieldControlProps extends Omit<\\n HTMLAttributes<HTMLElement>,\\n \'id\' | \'onChange\' | \'onBlur\'\\n> {\\n /**\\n * Merge accessible props into a custom child element instead of\\n * auto-rendering control.component.\\n */\\n asChild?: boolean;\\n /**\\n * Custom children. When provided, control.component is NOT auto-rendered.\\n * Accessible props are merged into the child via Slot.\\n */\\n children?: ReactNode;\\n}","summary":"Props for FormField.Control","description":"Props for FormField.Control","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldDescription","kind":"const","signature":"export const FormFieldDescription","summary":"FormField.Description - Helper text for the form field.","description":"FormField.Description - Helper text for the form field.\\n\\nRenders with a stable `id` (descriptionId) that can be wired to\\n`aria-describedby` on the control. To enable automatic wiring, pass\\n`hasDescription` to the parent `FormField.Root`.","params":[],"example":"```tsx\\n<FormField.Root control={control.email} hasDescription>\\n <FormField.Label />\\n <FormField.Control />\\n <FormField.Description className=\\"text-xs text-gray-500\\">\\n We\'ll never share your email with anyone.\\n </FormField.Description>\\n <FormField.Error />\\n</FormField.Root>\\n```","examplesCount":2,"sourcePath":"src/components/form-field/FormFieldDescription.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldDescriptionProps","kind":"interface","signature":"export interface FormFieldDescriptionProps extends Omit<\\n HTMLAttributes<HTMLParagraphElement>,\\n \'id\'\\n> {\\n asChild?: boolean;\\n children: ReactNode;\\n}","summary":"Props for FormField.Description","description":"Props for FormField.Description","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldError","kind":"const","signature":"export const FormFieldError","summary":"FormField.Error - Displays validation error message(s).","description":"FormField.Error - Displays validation error message(s).\\n\\nRenders nothing when `shouldShowError` is false (field not touched or no errors).\\nThe first error paragraph receives `id={ids.errorId}` for `aria-errormessage` wiring.","params":[],"example":"Single error (default)\\n```tsx\\n<FormField.Error className=\\"text-xs text-red-600\\" />\\n```","examplesCount":4,"sourcePath":"src/components/form-field/FormFieldError.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldErrorProps","kind":"interface","signature":"export interface FormFieldErrorProps extends Omit<\\n HTMLAttributes<HTMLParagraphElement>,\\n \'id\' | \'role\'\\n> {\\n asChild?: boolean;\\n /**\\n * When true, renders all errors instead of only the first.\\n * @default false\\n */\\n multi?: boolean;\\n /**\\n * Custom render function per error. When provided, multi is implied true.\\n */\\n render?: (error: ValidationError, index: number) => ReactNode;\\n /**\\n * Override error content. Defaults to errors[0].message.\\n */\\n children?: ReactNode;\\n}","summary":"Props for FormField.Error","description":"Props for FormField.Error","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldIds","kind":"interface","signature":"export interface FormFieldIds {\\n /** ID placed on the interactive control element (<input>, etc.) */\\n controlId: string;\\n /** ID placed on the <label> element */\\n labelId: string;\\n /** ID placed on the description paragraph */\\n descriptionId: string;\\n /** ID placed on the first error paragraph */\\n errorId: string;\\n}","summary":"Stable IDs for all accessible elements of a form field","description":"Stable IDs for all accessible elements of a form field","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldLabel","kind":"const","signature":"export const FormFieldLabel","summary":"FormField.Label - Accessible label for the form field.","description":"FormField.Label - Accessible label for the form field.\\n\\nAutomatically wires `htmlFor` to the control ID and `id` to the label ID\\nso that `aria-labelledby` on FormField.Control works correctly.\\n\\nThe label text defaults to `componentProps.label` from the field config.\\nPass `children` to override or enrich the label content.\\n\\nA required indicator `*` is appended automatically when `componentProps.required` is set.","params":[],"example":"Auto label from field config\\n```tsx\\n<FormField.Root control={control.email}>\\n<FormField.Label /> {/* renders componentProps.label *\\\\/}\\n<FormField.Control />\\n</FormField.Root>\\n```","examplesCount":3,"sourcePath":"src/components/form-field/FormFieldLabel.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldLabelProps","kind":"interface","signature":"export interface FormFieldLabelProps extends Omit<\\n LabelHTMLAttributes<HTMLLabelElement>,\\n \'htmlFor\'\\n> {\\n /** Render as child element via Slot (merges accessible props into the child) */\\n asChild?: boolean;\\n /**\\n * Override label text. Defaults to componentProps.label.\\n * Pass children explicitly when you need custom content inside the label.\\n */\\n children?: ReactNode;\\n /**\\n * If true, always renders even when no label text is available.\\n * Useful when the consumer provides children.\\n * @default false\\n */\\n forceRender?: boolean;\\n}","summary":"Props for FormField.Label","description":"Props for FormField.Label","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldRoot","kind":"function","signature":"function FormFieldRoot<T extends FormValue>({\\n control,\\n children,\\n id,\\n hasDescription = false,\\n}: FormFieldRootProps<T>)","summary":"FormField.Root - Context provider for form field compound component.","description":"FormField.Root - Context provider for form field compound component.\\n\\nComputes stable accessible IDs (controlId, labelId, descriptionId, errorId)\\nand provides all field state to child FormField.* components.","params":[],"example":"Minimal usage\\n```tsx\\n<FormField.Root control={control.email}>\\n<FormField.Label />\\n<FormField.Control />\\n<FormField.Error />\\n</FormField.Root>\\n```","examplesCount":2,"sourcePath":"src/components/form-field/FormFieldRoot.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormFieldRootProps","kind":"interface","signature":"export interface FormFieldRootProps<T extends FormValue = FormValue> {\\n /** The FieldNode control from the form */\\n control: FieldNode<T>;\\n children: ReactNode;\\n /** Explicit id prefix; if omitted, useId() is used */\\n id?: string;\\n /**\\n * Set to true when the field has a description element so that\\n * FormField.Control automatically wires aria-describedby.\\n * Avoids the double-render caused by dynamic description registration.\\n * @default false\\n */\\n hasDescription?: boolean;\\n}","summary":"Props for FormField.Root","description":"Props for FormField.Root","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/types.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"FormWizard","kind":"const","signature":"export const FormWizard","summary":"Headless-мастер многошаговой формы.","description":"Headless-мастер многошаговой формы. Compound-компонент: сам `FormWizard` держит состояние\\nшага/навигации/валидации, а под-компоненты подключаются к нему через контекст:\\n`FormWizard.Step` (рендер текущего шага), `FormWizard.Actions` (кнопки навигации),\\n`FormWizard.Indicator` и `FormWizard.Progress` (headless render-props), а также готовые\\nкнопки `FormWizard.Prev` / `FormWizard.Next` / `FormWizard.Submit`.\\n\\nЧисло шагов (`totalSteps`) выводится автоматически из количества `<FormWizard.Step>` в детях\\n(в т.ч. вложенных в обёрточные `div`). Валидация шага и всей формы — через колбэки в\\n{@link FormWizardConfig} (`validateStep` / `validateAll`), поэтому компонент не привязан к\\nконкретному движку валидации. Для внешнего управления (submit/переход из шапки страницы)\\nпробросьте `ref` типа {@link FormWizardHandle}.","params":[],"example":"Полный мастер с индикатором, действиями и прогрессом\\n```tsx\\nimport { useMemo, useRef } from \'react\';\\nimport { FormWizard, type FormWizardHandle } from \'@reformer/cdk/form-wizard\';\\n\\nconst STEPS = [\\n{ number: 1, title: \'Личные данные\' },\\n{ number: 2, title: \'Проверка\' },\\n];\\n\\nfunction Page({ form, model }: Props) {\\nconst navRef = useRef<FormWizardHandle<Profile>>(null);\\n// config: { validateStep, validateAll } — например, из makeValidationConfig(model)\\nconst config = useMemo(() => makeValidationConfig(model), [model]);\\n\\nreturn (\\n<FormWizard ref={navRef} form={form} config={config}>\\n<FormWizard.Indicator steps={STEPS}>\\n{({ steps, goToStep }) => (\\n <nav>\\n {steps.map((s) => (\\n <button key={s.number} onClick={() => goToStep(s.number)} disabled={!s.canNavigate}>\\n {s.title}\\n </button>\\n ))}\\n </nav>\\n)}\\n</FormWizard.Indicator>\\n\\n<FormWizard.Step component={PersonalStep} control={form} />\\n<FormWizard.Step component={ReviewStep} control={form} />\\n\\n<FormWizard.Actions onSubmit={() => navRef.current?.submit(api.save)}>\\n<FormWizard.Prev>Назад</FormWizard.Prev>\\n<FormWizard.Next>Далее</FormWizard.Next>\\n<FormWizard.Submit loadingText=\\"Отправка…\\">Отправить</FormWizard.Submit>\\n</FormWizard.Actions>\\n\\n<FormWizard.Progress>\\n{({ current, total, percent }) => <span>Шаг {current}/{total} ({percent}%)</span>}\\n</FormWizard.Progress>\\n</FormWizard>\\n);\\n}\\n```","examplesCount":1,"related":["FormWizardHandle","FormWizardConfig"],"topics":["overview","form-navigation","form-field","recipes","troubleshooting"],"sourcePath":"src/components/form-wizard/FormWizard.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk","usage":9},{"name":"FormWizardActions","kind":"function","signature":"export function FormWizardActions({\\n onSubmit,\\n children,\\n className,\\n style,\\n}: FormWizardActionsProps)","summary":"`FormWizard.Actions` — контейнер кнопок навигации мастера.","description":"`FormWizard.Actions` — контейнер кнопок навигации мастера. Поддерживает два режима:\\ncompound-children (`FormWizard.Prev`/`Next`/`Submit`) и render-props.\\n\\nRender-props получают: `prev`, `next`, `submit` (все с `onClick`/`disabled`),\\n`isFirstStep`, `isLastStep`, `isValidating`, `isSubmitting`.","params":[],"example":"Compound mode\\n```tsx\\n<FormWizard.Actions onSubmit={handleSubmit}>\\n<FormWizard.Prev>Back</FormWizard.Prev>\\n<FormWizard.Next>Next</FormWizard.Next>\\n<FormWizard.Submit loadingText=\\"Submitting...\\">Submit</FormWizard.Submit>\\n</FormWizard.Actions>\\n```","examplesCount":2,"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardActionsProps","kind":"interface","signature":"export interface FormWizardActionsProps {\\n /** Submit handler (called on last step) */\\n onSubmit?: () => void | Promise<void>;\\n /** Children: render function (headless) or ReactNode (compound components) */\\n children: ReactNode | RenderFunction;\\n /** Optional className for wrapper (compound mode only) */\\n className?: string;\\n /** Optional style for wrapper (compound mode only) */\\n style?: CSSProperties;\\n}","summary":"Props for FormWizard.Actions component","description":"Props for FormWizard.Actions component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardActionsRenderProps","kind":"interface","signature":"export interface FormWizardActionsRenderProps {\\n /** Props for the \\"Previous\\" button */\\n prev: FormWizardButtonProps;\\n /** Props for the \\"Next\\" button */\\n next: FormWizardButtonProps;\\n /** Props for the \\"Submit\\" button */\\n submit: FormWizardSubmitRenderProps;\\n /** Whether current step is the first step */\\n isFirstStep: boolean;\\n /** Whether current step is the last step */\\n isLastStep: boolean;\\n /** Whether validation is in progress */\\n isValidating: boolean;\\n /** Whether form is submitting */\\n isSubmitting: boolean;\\n}","summary":"Render props passed to children function","description":"Render props passed to children function","params":[],"examplesCount":0,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardButtonProps","kind":"interface","signature":"export interface FormWizardButtonProps {\\n /** Click handler */\\n onClick: () => void;\\n /** Whether the button is disabled */\\n disabled: boolean;\\n}","summary":"Props for a navigation button (prev/next)","description":"Props for a navigation button (prev/next)","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardConfig","kind":"interface","signature":"export interface FormWizardConfig {\\n /**\\n * M1: валидация шага (1-based) через колбэк (обычно — обёртка над\\n * `validateModel(model, stepSchema)` из `@reformer/core/validation`).\\n * Возвращает `true`, если шаг валиден. Нет колбэка → шаг считается валидным.\\n */\\n validateStep?: (step: number) => boolean | Promise<boolean>;\\n\\n /**\\n * M1: валидация всей формы перед submit. Нет колбэка → submit без блокировки.\\n */\\n validateAll?: () => boolean | Promise<boolean>;\\n}","summary":"Configuration for multi-step form navigation.","description":"Configuration for multi-step form navigation.\\nNote: totalSteps is inferred from children count. Валидация под M1 — через колбэки,\\nне зависит от типа формы, поэтому конфиг не дженерик.","params":[],"examplesCount":0,"topics":["form-navigation","recipes","troubleshooting"],"sourcePath":"src/components/form-wizard/types.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardContext","kind":"const","signature":"export const FormWizardContext","summary":"React context, который снабжает дочерние компоненты `FormWizard` (Step, Actions, Indicator, Progress) текущим состоянием мастера.","description":"React context, который снабжает дочерние компоненты `FormWizard` (Step,\\nActions, Indicator, Progress) текущим состоянием мастера. Создаётся\\n`FormWizard`. Читать через `useFormWizard()`.","params":[],"example":"```tsx\\nimport { FormWizardContext } from \'@reformer/cdk/form-wizard\';\\n\\nfunction CurrentStep() {\\n const ctx = useContext(FormWizardContext);\\n return <span>step {ctx?.currentStep}</span>;\\n}\\n```","examplesCount":1,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardContext.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardContextValue","kind":"interface","signature":"export interface FormWizardContextValue<T extends Record<string, any>> {\\n // ============================================================================\\n // State\\n // ============================================================================\\n\\n /** Current step (1-based) */\\n currentStep: number;\\n\\n /** Total number of steps */\\n totalSteps: number;\\n\\n /** Completed steps */\\n completedSteps: number[];\\n\\n /** Is this the first step */\\n isFirstStep: boolean;\\n\\n /** Is this the last step */\\n isLastStep: boolean;\\n\\n /** Is validation in progress */\\n isValidating: boolean;\\n\\n /** Is form submitting */\\n isSubmitting: boolean;\\n\\n /** Form instance */\\n form: FormProxy<T>;\\n\\n // ============================================================================\\n // Navigation Methods\\n // ============================================================================\\n\\n /** Go to next step (with validation) */\\n goToNextStep: () => Promise<boolean>;\\n\\n /** Go to previous step */\\n goToPreviousStep: () => void;\\n\\n /** Go to specific step */\\n goToStep: (step: number) => boolean;\\n\\n // ============================================================================\\n // Submit\\n // ============================================================================\\n\\n /**\\n * Отправить форму с полной валидацией. Прогоняет `config.validateAll` и только при\\n * успехе зовёт `onSubmit` через `form.submit(..., { skipValidation: true })`.\\n *\\n * Возвращает `null`, если форма не прошла `validateAll` (поля при этом помечаются\\n * `touched`, чтобы ошибки стали видны); иначе — результат `onSubmit`.\\n *\\n * Тот же метод, что и {@link FormWizardHandle.submit}: он положен в контекст, чтобы\\n * кнопка отправки (`FormWizard.Actions` / `FormWizard.Submit`) гейтила submit так же,\\n * как `goToNextStep` гейтит переход на следующий шаг.\\n */\\n submit: <R>(onSubmit: (values: T) => Promise<R> | R) => Promise<R | null>;\\n}","summary":"Context value for FormWizard Shares navigation state and methods with child components","description":"Context value for FormWizard\\nShares navigation state and methods with child components","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardContext.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardHandle","kind":"interface","signature":"export interface FormWizardHandle<T extends Record<string, any>> {\\n /** Form instance — используется в RenderBehaviorFn для доступа к форме через ref */\\n form: FormProxy<T>;\\n\\n /** Current step (1-based) */\\n currentStep: number;\\n\\n /** Completed steps */\\n completedSteps: number[];\\n\\n /** Validate current step */\\n validateCurrentStep: () => Promise<boolean>;\\n\\n /** Go to next step (with validation) */\\n goToNextStep: () => Promise<boolean>;\\n\\n /** Go to previous step */\\n goToPreviousStep: () => void;\\n\\n /** Go to specific step */\\n goToStep: (step: number) => boolean;\\n\\n /** Submit form (with full validation) */\\n submit: <R>(onSubmit: (values: T) => Promise<R> | R) => Promise<R | null>;\\n\\n /** Is this the first step */\\n isFirstStep: boolean;\\n\\n /** Is this the last step */\\n isLastStep: boolean;\\n\\n /** Is validation in progress */\\n isValidating: boolean;\\n}","summary":"Handle для внешнего управления {@link FormWizard} через `useRef`.","description":"Handle для внешнего управления {@link FormWizard} через `useRef`.\\n\\nИспользуется, когда submit/навигация инициируется снаружи дерева Wizard:\\nшапка страницы, breadcrumbs, side-effect от API. Получают через\\n`useRef<FormWizardHandle<T>>(null)` и передают в `<FormWizard ref={...}>`.\\n\\n- `goToNextStep()` / `submit()` запускают валидацию текущего шага / всей\\n формы соответственно.\\n- `goToStep(n)` возвращает `false`, если предыдущий шаг не в `completedSteps`\\n (защита от пропуска валидации) либо `n` вне диапазона `[1; totalSteps]`.\\n- `submit()` возвращает `R | null`. `null` — форма не прошла `validateAll`.","params":[],"example":"«Сохранить и выйти» поверх wizard\\n```tsx\\nimport { useRef } from \'react\';\\nimport { FormWizard, type FormWizardHandle } from \'@reformer/cdk/form-wizard\';\\n\\nfunction Page({ form, config }: Props) {\\nconst navRef = useRef<FormWizardHandle<CreditApplication>>(null);\\n\\nconst handleSaveAndExit = async () => {\\nconst saved = await navRef.current?.submit((values) => api.saveDraft(values));\\nif (saved) router.push(\'/dashboard\');\\n};\\n\\nreturn (\\n<>\\n<header>\\n<button onClick={handleSaveAndExit}>Сохранить и выйти</button>\\n</header>\\n<FormWizard ref={navRef} form={form} config={config}>\\n<FormWizard.Step component={Step1} control={form} />\\n<FormWizard.Step component={Step2} control={form} />\\n</FormWizard>\\n</>\\n);\\n}\\n```","examplesCount":2,"topics":["form-navigation","recipes","troubleshooting"],"sourcePath":"src/components/form-wizard/types.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk","usage":5},{"name":"FormWizardIndicator","kind":"function","signature":"export function FormWizardIndicator({ steps, children }: FormWizardIndicatorProps)","summary":"FormWizard.Indicator - Headless component for step indicator Provides step data with state for building custom step indicators.","description":"FormWizard.Indicator - Headless component for step indicator\\n\\nProvides step data with state for building custom step indicators.\\nNo default UI - you build exactly what you need.\\n\\n## Render Props\\n- `steps` - array of steps with state (`isCurrent`, `isCompleted`, `canNavigate`)\\n- `goToStep` - function to navigate to a step\\n- `currentStep` - current step number\\n- `totalSteps` - total number of steps\\n- `completedSteps` - array of completed step numbers","params":[],"example":"Basic stepper\\n```tsx\\n<FormWizard.Indicator steps={STEPS}>\\n{({ steps, goToStep }) => (\\n<nav className=\\"flex gap-2\\">\\n{steps.map((step) => (\\n<button\\n key={step.number}\\n onClick={() => goToStep(step.number)}\\n disabled={!step.canNavigate}\\n className={cn(\\n \'px-4 py-2 rounded\',\\n step.isCurrent && \'bg-blue-500 text-white\',\\n step.isCompleted && \'bg-green-100\',\\n !step.canNavigate && \'opacity-50 cursor-not-allowed\'\\n )}\\n>\\n {step.icon} {step.title}\\n</button>\\n))}\\n</nav>\\n)}\\n</FormWizard.Indicator>\\n```","examplesCount":2,"sourcePath":"src/components/form-wizard/FormWizardIndicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardIndicatorProps","kind":"interface","signature":"export interface FormWizardIndicatorProps {\\n /** Step definitions */\\n steps: FormWizardIndicatorStep[];\\n /** Render function for custom UI */\\n children: (props: FormWizardIndicatorRenderProps) => ReactNode;\\n}","summary":"Props for FormWizard.Indicator component","description":"Props for FormWizard.Indicator component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardIndicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardIndicatorRenderProps","kind":"interface","signature":"export interface FormWizardIndicatorRenderProps {\\n /** Steps with their current state */\\n steps: FormWizardIndicatorStepWithState[];\\n /** Navigate to a specific step */\\n goToStep: (step: number) => boolean;\\n /** Current step number */\\n currentStep: number;\\n /** Total number of steps */\\n totalSteps: number;\\n /** Completed step numbers */\\n completedSteps: number[];\\n}","summary":"Render props passed to children function","description":"Render props passed to children function","params":[],"examplesCount":0,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardIndicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardIndicatorStep","kind":"interface","signature":"export interface FormWizardIndicatorStep {\\n /** Step number (1-based) */\\n number: number;\\n /** Step title/label */\\n title: string;\\n /** Optional icon */\\n icon?: string;\\n /** Component to render for this step, or a ReactNode (pre-rendered element) */\\n component?:\\n | ComponentType<\\n {\\n control: FormProxy<unknown>;\\n } & Record<string, unknown>\\n >\\n | ReactNode;\\n}","summary":"Step definition for the indicator","description":"Step definition for the indicator","params":[],"examplesCount":0,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardIndicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardIndicatorStepWithState","kind":"interface","signature":"export interface FormWizardIndicatorStepWithState extends FormWizardIndicatorStep {\\n /** Whether this is the current step */\\n isCurrent: boolean;\\n /** Whether this step is completed */\\n isCompleted: boolean;\\n /** Whether user can navigate to this step */\\n canNavigate: boolean;\\n}","summary":"Enriched step with state information","description":"Enriched step with state information","params":[],"examplesCount":0,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardIndicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardNext","kind":"const","signature":"export const FormWizardNext","summary":"FormWizard.Next - Next step button component Renders a button that validates current step and navigates to the next.","description":"FormWizard.Next - Next step button component\\n\\nRenders a button that validates current step and navigates to the next.\\nAutomatically disabled on the last step, during validation, or during submission.","params":[],"example":"Basic usage\\n```tsx\\n<FormWizard.Actions>\\n<FormWizard.Next>Continue</FormWizard.Next>\\n</FormWizard.Actions>\\n```","examplesCount":2,"sourcePath":"src/components/form-wizard/FormWizardNext.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardNextProps","kind":"interface","signature":"export interface FormWizardNextProps extends Omit<\\n ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Button content */\\n children: ReactNode;\\n /** Render as child element (merge props into child) */\\n asChild?: boolean;\\n /** Additional disabled state (merged with automatic via OR) */\\n disabled?: boolean;\\n}","summary":"Props for FormWizard.Next component","description":"Props for FormWizard.Next component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardNext.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardPrev","kind":"const","signature":"export const FormWizardPrev","summary":"FormWizard.Prev - Previous step button component Renders a button that navigates to the previous step.","description":"FormWizard.Prev - Previous step button component\\n\\nRenders a button that navigates to the previous step.\\nAutomatically disabled on the first step, during validation, or during submission.","params":[],"example":"Basic usage\\n```tsx\\n<FormWizard.Actions>\\n<FormWizard.Prev>Back</FormWizard.Prev>\\n</FormWizard.Actions>\\n```","examplesCount":2,"sourcePath":"src/components/form-wizard/FormWizardPrev.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardPrevProps","kind":"interface","signature":"export interface FormWizardPrevProps extends Omit<\\n ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Button content */\\n children: ReactNode;\\n /** Render as child element (merge props into child) */\\n asChild?: boolean;\\n /** Additional disabled state (merged with automatic via OR) */\\n disabled?: boolean;\\n}","summary":"Props for FormWizard.Prev component","description":"Props for FormWizard.Prev component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardPrev.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardProgress","kind":"function","signature":"export function FormWizardProgress({ children }: FormWizardProgressProps)","summary":"FormWizard.Progress - Headless component for progress display Provides progress data for building custom progress indicators.","description":"FormWizard.Progress - Headless component for progress display\\n\\nProvides progress data for building custom progress indicators.\\nNo default UI - you build exactly what you need.\\n\\n## Render Props\\n- `current` - current step number\\n- `total` - total number of steps\\n- `percent` - completion percentage (0-100)\\n- `completedCount` - number of completed steps\\n- `isFirstStep` - whether on first step\\n- `isLastStep` - whether on last step","params":[],"example":"Simple text progress\\n```tsx\\n<FormWizard.Progress>\\n{({ current, total, percent }) => (\\n<div className=\\"text-sm text-gray-600\\">\\nStep {current} of {total} ({percent}% complete)\\n</div>\\n)}\\n</FormWizard.Progress>\\n```","examplesCount":3,"sourcePath":"src/components/form-wizard/FormWizardProgress.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardProgressProps","kind":"interface","signature":"export interface FormWizardProgressProps {\\n /** Render function for custom UI */\\n children: (props: FormWizardProgressRenderProps) => ReactNode;\\n}","summary":"Props for FormWizard.Progress component","description":"Props for FormWizard.Progress component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardProgress.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardProgressRenderProps","kind":"interface","signature":"export interface FormWizardProgressRenderProps {\\n /** Current step number (1-based) */\\n current: number;\\n /** Total number of steps */\\n total: number;\\n /** Completion percentage (0-100) */\\n percent: number;\\n /** Number of completed steps */\\n completedCount: number;\\n /** Whether on first step */\\n isFirstStep: boolean;\\n /** Whether on last step */\\n isLastStep: boolean;\\n}","summary":"Render props passed to children function","description":"Render props passed to children function","params":[],"examplesCount":0,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/FormWizardProgress.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardProps","kind":"interface","signature":"export interface FormWizardProps<T extends Record<string, any>> {\\n /** Form instance */\\n form: FormProxy<T>;\\n\\n /** Step configuration (validation callbacks) */\\n config: FormWizardConfig;\\n\\n /** Children (Step components, Indicator, Actions, Progress, or any ReactNode) */\\n children?: ReactNode;\\n\\n /** Callback when step changes */\\n onStepChange?: (step: number) => void;\\n\\n /** Scroll to top on step change */\\n scrollToTop?: boolean;\\n}","summary":"Props for FormWizard component","description":"Props for FormWizard component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/types.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardStep","kind":"function","signature":"export function FormWizardStep<T extends Record<string, any>>({\\n component: Component,\\n control,\\n children,\\n _stepIndex,\\n ...restProps\\n}: FormWizardStepInternalProps<T>)","summary":"FormWizard.Step - renders a step component when it\'s the current step","description":"FormWizard.Step - renders a step component when it\'s the current step","params":[],"example":"Component-based (legacy)\\n```tsx\\n<FormWizard ref={navRef} form={form} config={config}>\\n<FormWizard.Step component={Step1} control={form} />\\n<FormWizard.Step component={Step2} control={form} extraProp=\\"value\\" />\\n</FormWizard>\\n```","examplesCount":2,"topics":["recipes"],"sourcePath":"src/components/form-wizard/FormWizardStep.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk","usage":2},{"name":"FormWizardStepProps","kind":"interface","signature":"export interface FormWizardStepProps<T extends Record<string, any>> {\\n /** Component to render for this step (legacy API) */\\n component?: ComponentType<{ control: FormProxy<T> } & Record<string, unknown>>;\\n\\n /** Form control to pass to the component (legacy API) */\\n control?: FormProxy<T>;\\n\\n /** Children to render (new API - for use with selector-based wizard) */\\n children?: ReactNode;\\n\\n /** Any additional props to pass to the component */\\n [key: string]: unknown;\\n}","summary":"Props for FormWizard.Step component Supports two usage patterns: 1.","description":"Props for FormWizard.Step component\\n\\nSupports two usage patterns:\\n1. Component-based: `<FormWizard.Step component={Step1} control={form} />`\\n2. Children-based: `<FormWizard.Step>{children}</FormWizard.Step>`","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardStep.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardSubmit","kind":"const","signature":"export const FormWizardSubmit","summary":"FormWizard.Submit - Form submission button component Renders a button that submits the form on the last step.","description":"FormWizard.Submit - Form submission button component\\n\\nRenders a button that submits the form on the last step.\\nAutomatically disabled when not on the last step, during validation, or during submission.\\nShows `loadingText` content during submission if provided.","params":[],"example":"Basic usage\\n```tsx\\n<FormWizard.Actions onSubmit={handleSubmit}>\\n<FormWizard.Submit>Submit</FormWizard.Submit>\\n</FormWizard.Actions>\\n```","examplesCount":3,"sourcePath":"src/components/form-wizard/FormWizardSubmit.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardSubmitProps","kind":"interface","signature":"export interface FormWizardSubmitProps extends Omit<\\n ButtonHTMLAttributes<HTMLButtonElement>,\\n \'onClick\'\\n> {\\n /** Button content */\\n children: ReactNode;\\n /** Render as child element (merge props into child) */\\n asChild?: boolean;\\n /** Additional disabled state (merged with automatic via OR) */\\n disabled?: boolean;\\n /** Content to show during submission (replaces children) */\\n loadingText?: ReactNode;\\n}","summary":"Props for FormWizard.Submit component","description":"Props for FormWizard.Submit component","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardSubmit.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk"},{"name":"FormWizardSubmitRenderProps","kind":"interface","signature":"export interface FormWizardSubmitRenderProps extends FormWizardButtonProps {\\n /** Whether form is currently submitting */\\n isSubmitting: boolean;\\n}","summary":"Render-props state for the submit button (headless mode).","description":"Render-props state for the submit button (headless mode).\\nRenamed from `FormWizardSubmitProps` to avoid a name collision with the\\n`FormWizardSubmitProps` component props in FormWizardSubmit.tsx.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"initialAsyncResourceState","kind":"function","signature":"export function initialAsyncResourceState<T, E>(): AsyncResourceState<T, E>","summary":"Начальное состояние: до первого эффекта загрузка ещё не запускалась.","description":"Начальное состояние: до первого эффекта загрузка ещё не запускалась.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/async-resource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"initialFileUploadState","kind":"function","signature":"export function initialFileUploadState(): FileUploadState","summary":"Начальное состояние: пустой список.","description":"Начальное состояние: пустой список.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"List","kind":"const","signature":"export const List","summary":"List — headless compound для display-итерации массива модели.","description":"List — headless compound для display-итерации массива модели.\\n\\nRead-only брат {@link FormArray}: перебирает элементы массива и рендерит на каждый произвольную\\nразметку, БЕЗ кнопок add/remove/reorder. Для списков, которые не редактируются пользователем, а\\nпоказываются/скрываются через мутацию массива в behavior (например, алерты).\\n\\n## Sub-components\\n- `List.Root` — контекст-провайдер (принимает `control`)\\n- `List.Items` — итерация элементов (render-prop `{ control, index, id }`)\\n- `List.Empty` — содержимое пустого состояния","params":[],"example":"```tsx\\n<List.Root control={form.alerts}>\\n <List.Empty><p className=\\"text-gray-400\\">Нет уведомлений</p></List.Empty>\\n <List.Items className=\\"space-y-2\\">\\n {({ control }) => <Alert control={control} />}\\n </List.Items>\\n</List.Root>\\n```","examplesCount":1,"topics":["form-array","recipes","troubleshooting"],"sourcePath":"src/components/list/List.tsx","entries":[".","./list"],"package":"@reformer/cdk","usage":9},{"name":"ListContext","kind":"const","signature":"export const ListContext","summary":"React-контекст, снабжающий дочерние компоненты `List` (`Items`/`Empty`) текущими элементами.","description":"React-контекст, снабжающий дочерние компоненты `List` (`Items`/`Empty`) текущими элементами.\\nСоздаётся `List.Root`. Читать через {@link useListContext}.","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListContextValue","kind":"interface","signature":"export interface ListContextValue<T extends object = Record<string, unknown>> {\\n /** Элементы списка с их контролами */\\n items: ListItem<T>[];\\n /** Текущая длина списка */\\n length: number;\\n /** Пустой ли список */\\n isEmpty: boolean;\\n}","summary":"Контекст уровня списка.","description":"Контекст уровня списка. Read-only: только `items` + производные (`length`/`isEmpty`), без\\nмутационных действий (ср. {@link FormArrayContextValue}).","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListControl","kind":"type","signature":"export type ListControl<T extends object> = ArrayNode<T> | ModelArrayNode<T>;","summary":"Узел массива, принимаемый CDK-компонентом {@link List}.","description":"Узел массива, принимаемый CDK-компонентом {@link List}.\\n\\nИдентичен {@link FormArrayControl} — legacy {@link ArrayNode} (владеет элементами) ИЛИ M1\\n{@link ModelArrayNode} (делегирует массиву модели). `List` использует лишь read-часть контракта\\n(`map`/`at`/`length`/`value`), поэтому мутационные методы здесь не нужны, но union тот же:\\nконсументы M1 (у которых `form.<field>` материализуется как ModelArrayNode) не должны кастовать.","params":[],"examplesCount":0,"sourcePath":"src/components/list/types.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListEmptyProps","kind":"interface","signature":"export interface ListEmptyProps {\\n /** Содержимое, показываемое когда список пуст */\\n children: ReactNode;\\n}","summary":"Props for List.Empty component","description":"Props for List.Empty component","params":[],"examplesCount":0,"sourcePath":"src/components/list/types.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListItem","kind":"interface","signature":"export interface ListItem<T extends object> {\\n /** Контрол для данного элемента */\\n control: FormProxy<T>;\\n /** Индекс элемента (0-based) */\\n index: number;\\n /** Уникальный идентификатор для React key */\\n id: string | number;\\n}","summary":"Один элемент списка — контрол, индекс и стабильный ключ.","description":"Один элемент списка — контрол, индекс и стабильный ключ. В отличие от\\n{@link FormArrayItemRenderProps} НЕ несёт мутационных/reorder-хелперов: `List` — display-итерация.","params":[],"examplesCount":0,"sourcePath":"src/components/list/types.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListItemContext","kind":"const","signature":"export const ListItemContext","summary":"React-контекст текущего элемента, видимый внутри `List.Items`.","description":"React-контекст текущего элемента, видимый внутри `List.Items`. Читать через\\n{@link useListItemContext}.","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListItemContextValue","kind":"type","signature":"export type ListItemContextValue<T extends object = Record<string, unknown>> = ListItem<T>;","summary":"Контекст уровня элемента внутри {@link List.Items}.","description":"Контекст уровня элемента внутри {@link List.Items}.","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListItemsProps","kind":"interface","signature":"export interface ListItemsProps<T extends object> {\\n /** Render-функция для каждого элемента */\\n children: (item: ListItem<T>) => ReactNode;\\n /** Опциональный className контейнера */\\n className?: string;\\n /** Опциональный тег контейнера (по умолчанию Fragment, если нет className) */\\n as?: ElementType;\\n}","summary":"Props for List.Items component","description":"Props for List.Items component","params":[],"examplesCount":0,"sourcePath":"src/components/list/types.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"ListRootProps","kind":"interface","signature":"export interface ListRootProps<T extends object> {\\n /** Массив-контрол из формы — legacy ArrayNode или M1 ModelArrayNode */\\n control: ListControl<T>;\\n /** Дочерние компоненты */\\n children: ReactNode;\\n}","summary":"Props for List.Root component","description":"Props for List.Root component","params":[],"examplesCount":0,"sourcePath":"src/components/list/types.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"makeFileError","kind":"function","signature":"export function makeFileError(code: string, params?: FileError[\'params\']): FileError","summary":"Ошибка отбора с дефолтным `message: \'invalid\'` (текст даёт резолвер сообщений).","description":"Ошибка отбора с дефолтным `message: \'invalid\'` (текст даёт резолвер сообщений).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"projectValue","kind":"function","signature":"export function projectValue(items: FileUploadItem[], mode: \'local\' | \'remote\'): FileUploadValue","summary":"Проекция внутреннего списка в значение поля формы.","description":"Проекция внутреннего списка в значение поля формы.\\n\\n- `\'local\'` (deferred-режим): все файлы списка → `File[]`.\\n- `\'remote\'` (uploader-режим): ТОЛЬКО `uploaded`-элементы → `RemoteFileRef[]` —\\n значение всегда сериализуемо; `uploading`/`error` в форму не попадают\\n (файл не догружен — его нет).\\n\\nПустой результат — `null`, чтобы `required()` срабатывал без изменений.","params":[["items","- Внутренний список."],["mode","- Режим проекции."]],"returns":"Значение поля.","examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"reconcileItems","kind":"function","signature":"export function reconcileItems(\\n items: FileUploadItem[],\\n value: FileUploadValue,\\n mode: \'local\' | \'remote\',\\n makeKey: (file: File) => string\\n): FileUploadItem[]","summary":"Пересборка списка под внешнее значение формы (reset/patchValue снаружи).","description":"Пересборка списка под внешнее значение формы (reset/patchValue снаружи).\\n\\nВнешняя запись авторитетна: элементы, не представленные в значении (включая\\nнезавершённые загрузки), выбывают — их abort-очистку делает хук. Существующие\\nэлементы матчятся, чтобы сохранить `key` (превью, DOM-стабильность):\\nв `\'local\'`-режиме — по ссылке `File`, в `\'remote\'` — по `remote.id`\\n(незнакомый дескриптор становится `uploaded`-элементом без `file` — preloaded\\nпри редактировании формы).","params":[["items","- Текущий список."],["value","- Внешнее значение поля."],["mode","- Режим проекции."],["makeKey","- Генератор ключей для новых `File` (у ключей hook-счётчик)."]],"returns":"Новый список.","examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"RemoteFileRef","kind":"interface","signature":"export interface RemoteFileRef {\\n /** Идентификатор файла на сервере — по нему матчится восстановление и revert. */\\n id: string;\\n /** Имя файла для отображения. */\\n name: string;\\n /** URL для скачивания/превью, если сервер его отдаёт. */\\n url?: string;\\n /** Размер в байтах, если известен. */\\n size?: number;\\n /** MIME-тип, если известен. */\\n type?: string;\\n /** Произвольные сериализуемые данные бэкенда (bucket, версия и т.п.). */\\n meta?: Record<string, string | number | boolean | null>;\\n}","summary":"Сериализуемый дескриптор загруженного файла (uploader-режим).","description":"Сериализуемый дескриптор загруженного файла (uploader-режим).\\n\\nИменно он попадает в значение поля формы вместо `File`: `File` не сериализуется\\nв JSON, а дескриптор переживает черновики, `renderer-json` и восстановление\\nформы при редактировании (preloaded-файлы).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk","usage":7},{"name":"selectFiles","kind":"function","signature":"export function selectFiles(\\n candidates: File[],\\n options: SelectFilesOptions,\\n existing: FileUploadItem[]\\n): SelectFilesResult","summary":"Отбор кандидатов (выбор в пикере, drop, paste, программный `addFiles`).","description":"Отбор кандидатов (выбор в пикере, drop, paste, программный `addFiles`).\\n\\nКаждый файл проверяется на тип/размер/дубликат/кастомные правила — все нарушения\\nсобираются в ОДНУ rejection (`errors[]`), как у react-dropzone/Ark UI. Затем\\nприменяются коллективные лимиты: переполнение `maxFiles`/`maxTotalFileSize`\\nотклоняет лишние файлы (не весь дроп) с кодами `maxFiles`/`maxTotalFileSize`.\\n\\nПри `multiple: false` лимит — один файл; замену текущего выбора организует\\nвызывающий код (передаёт `existing: []` и `replace: true` в действии `add`).","params":[["candidates","- Файлы-кандидаты в порядке поступления."],["options","- Правила отбора."],["existing","- Текущий список (для дубликатов и коллективных лимитов)."]],"returns":"Принятые и отклонённые файлы.","examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"SelectFilesOptions","kind":"interface","signature":"export interface SelectFilesOptions {\\n accept?: string;\\n multiple?: boolean;\\n maxFiles?: number;\\n maxFileSize?: number;\\n minFileSize?: number;\\n maxTotalFileSize?: number;\\n preventDuplicates?: boolean;\\n validate?: (file: File, ctx: { existing: FileUploadItem[] }) => FileError[] | null;\\n}","summary":"Правила отбора — подмножество опций {@link UseFileUploadOptions}.","description":"Правила отбора — подмножество опций {@link UseFileUploadOptions}.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"SelectFilesResult","kind":"interface","signature":"export interface SelectFilesResult {\\n accepted: File[];\\n rejected: FileRejection[];\\n}","summary":"Итог отбора: что добавить в список и что отдать в `onReject`.","description":"Итог отбора: что добавить в список и что отдать в `onReject`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-core.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"Slot","kind":"const","signature":"export const Slot","summary":"Slot component for asChild pattern.","description":"Slot component for asChild pattern.\\n\\nRenders its child element and merges props from the Slot into the child.\\nUsed to allow custom components to be rendered in place of default elements.","params":[],"example":"```tsx\\n// Instead of rendering a button, renders MyButton with merged props\\n<Slot onClick={handleClick} disabled={true}>\\n <MyButton className=\\"custom\\">Click me</MyButton>\\n</Slot>\\n// Result: <MyButton onClick={handleClick} disabled={true} className=\\"custom\\">Click me</MyButton>\\n```","examplesCount":1,"topics":["form-field","recipes"],"sourcePath":"src/components/form-wizard/Slot.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"SlotProps","kind":"interface","signature":"export interface SlotProps extends HTMLAttributes<HTMLElement> {\\n children?: ReactNode;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/Slot.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"Step","kind":"function","signature":"export function Step({ children }: StepProps): ReactNode","summary":"Step - маркер-компонент для wizard-схемы Компонент просто рендерит children.","description":"Step - маркер-компонент для wizard-схемы\\n\\nКомпонент просто рендерит children. Метаданные (title, icon) извлекаются\\nwizard-компонентом из componentProps через useFormWizardSelectors.","params":[],"examplesCount":0,"topics":["form-navigation","recipes","troubleshooting"],"sourcePath":"src/components/form-wizard/Step.tsx","entries":["./form-wizard"],"package":"@reformer/cdk","usage":20},{"name":"StepProps","kind":"interface","signature":"export interface StepProps {\\n /** Заголовок шага (отображается в индикаторе) */\\n title: string;\\n /** Иконка шага (emoji или текст) */\\n icon?: string;\\n /** CSS класс */\\n className?: string;\\n /** Дочерние элементы */\\n children?: ReactNode;\\n}","summary":"Props для Step компонента","description":"Props для Step компонента","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/Step.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"StepValidationConfig","kind":"interface","signature":"export interface StepValidationConfig {\\n createStepController: (step: number) => FormValidationController | null;\\n}","summary":"Минимум от {@link WizardStepsConfig}, нужный хуку: фабрика контроллера live-стратегии шага.","description":"Минимум от {@link WizardStepsConfig}, нужный хуку: фабрика контроллера live-стратегии шага.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/use-wizard-step-validation.ts","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"useAsyncBoundary","kind":"function","signature":"export function useAsyncBoundary<E = unknown>({\\n status,\\n error = null,\\n refreshing = false,\\n onRetry,\\n delayMs = 0,\\n id,\\n}: UseAsyncBoundaryOptions<E>): UseAsyncBoundaryReturn<E>","summary":"Headless-хук состояний асинхронной загрузки: нормализует статус, гасит вспышку спиннера и отдаёт готовые наборы a11y-пропсов.","description":"Headless-хук состояний асинхронной загрузки: нормализует статус, гасит вспышку\\nспиннера и отдаёт готовые наборы a11y-пропсов.\\n\\nИспользуется самим `AsyncBoundary.Root`, но пригоден и отдельно — когда разметка\\nпишется вручную и compound-дерево избыточно.","params":[["options","- Статус, ошибка, `onRetry`, `delayMs`, `id`."]],"returns":"Разложенный статус, `retry` и три набора пропсов (`rootProps` / `loadingProps` / `errorProps`).","example":"Ручная разметка без compound-дерева\\n```tsx\\nimport { useAsyncBoundary } from \'@reformer/cdk/async-boundary\';\\n\\nfunction Panel({ status, error, reload, children }: Props) {\\nconst { isLoading, isError, retry, rootProps, loadingProps, errorProps } =\\nuseAsyncBoundary({ status, error, onRetry: reload, delayMs: 200 });\\n\\nreturn (\\n<section {...rootProps}>\\n{isLoading && <p {...loadingProps}>Загрузка…</p>}\\n{isError && (\\n<div {...errorProps}>\\n {error}\\n <button onClick={retry}>Повторить</button>\\n</div>\\n)}\\n{!isLoading && !isError && children}\\n</section>\\n);\\n}\\n```","examplesCount":2,"topics":["overview","async-boundary"],"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"useAsyncBoundaryContext","kind":"function","signature":"export function useAsyncBoundaryContext<T = unknown, E = unknown>(): AsyncBoundaryContextValue<\\n T,\\n E\\n>","summary":"Хук доступа к контексту `AsyncBoundary`.","description":"Хук доступа к контексту `AsyncBoundary`. Бросает исключение вне `AsyncBoundary.Root`.","params":[],"returns":"Текущее {@link AsyncBoundaryContextValue}.","example":"Своя кнопка повтора вне слота Error\\n```tsx\\nimport { useAsyncBoundaryContext } from \'@reformer/cdk/async-boundary\';\\n\\nfunction ToolbarRetry() {\\nconst { isError, retry, canRetry } = useAsyncBoundaryContext<string>();\\nif (!isError || !canRetry) return null;\\nreturn <button onClick={retry}>Повторить загрузку</button>;\\n}\\n```","examplesCount":2,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/AsyncBoundaryContext.tsx","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"UseAsyncBoundaryOptions","kind":"interface","signature":"export interface UseAsyncBoundaryOptions<E = unknown> {\\n /** Текущее состояние асинхронной операции. */\\n status: AsyncStatus;\\n /** Полезная нагрузка ошибки. */\\n error?: E | null;\\n /** Фоновое обновление поверх уже показанного контента. @default false */\\n refreshing?: boolean;\\n /** Повтор загрузки. */\\n onRetry?: () => void;\\n /** Задержка перед показом загрузки, мс. @default 0 */\\n delayMs?: number;\\n /** Явный префикс для генерируемых id. */\\n id?: string;\\n}","summary":"Опции {@link useAsyncBoundary}.","description":"Опции {@link useAsyncBoundary}. Совпадают с props `AsyncBoundary.Root`.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"UseAsyncBoundaryReturn","kind":"interface","signature":"export interface UseAsyncBoundaryReturn<E = unknown> {\\n status: AsyncStatus;\\n isIdle: boolean;\\n /** Учитывает `delayMs` — см. {@link UseAsyncBoundaryOptions.delayMs}. */\\n isLoading: boolean;\\n isReady: boolean;\\n isError: boolean;\\n refreshing: boolean;\\n error: E | null;\\n retry: () => void;\\n canRetry: boolean;\\n ids: AsyncBoundaryIds;\\n rootProps: AsyncBoundaryRootPropGetters;\\n loadingProps: AsyncBoundaryLoadingPropGetters;\\n errorProps: AsyncBoundaryErrorPropGetters;\\n}","summary":"Возвращаемое значение {@link useAsyncBoundary}.","description":"Возвращаемое значение {@link useAsyncBoundary}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncBoundary.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"useAsyncResource","kind":"function","signature":"export function useAsyncResource<T, E = string>({\\n load,\\n loadKey,\\n enabled = true,\\n onSuccess,\\n onError,\\n toError,\\n}: UseAsyncResourceOptions<T, E>): UseAsyncResourceReturn<T, E>","summary":"Хук асинхронной загрузки с отменой, повтором и stale-while-revalidate.","description":"Хук асинхронной загрузки с отменой, повтором и stale-while-revalidate.\\n\\nТонкая React-обёртка над чистым редьюсером из `async-resource.ts` — вся логика\\nпереходов там и тестируется без DOM.\\n\\nЗакрывает три дыры, типичные для рукописных `useEffect`-загрузчиков:\\nгонку при быстрой смене `loadKey` (побеждал бы ответ, пришедший последним),\\nотсутствие повтора и потерю состояния «грузить нечего».","params":[["options","- См. {@link UseAsyncResourceOptions}."]],"returns":"Состояние загрузки плюс `reload` / `abort`.","example":"Загрузка заявки со справочниками как одна единица\\n```tsx\\nconst { status, error, reload } = useAsyncResource({\\nloadKey: applicationId,\\nenabled: applicationId !== null,\\nload: async (signal) => {\\nconst [app, dict] = await Promise.all([\\nfetchCreditApplication(applicationId!, signal),\\nfetchDictionaries(signal),\\n]);\\nif (app.status !== 200) throw new Error(\'Ошибка загрузки заявки\');\\nif (dict.status !== 200) throw new Error(\'Ошибка загрузки справочников\');\\nreturn { app: app.data, dict: dict.data };\\n},\\nonSuccess: ({ app, dict }) => {\\nform.patchValue(app);\\nqueueMicrotask(() => applyDictionaries(form, dict));\\n},\\n});\\n```","examplesCount":2,"topics":["async-boundary"],"sourcePath":"src/components/async-boundary/useAsyncResource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"UseAsyncResourceOptions","kind":"interface","signature":"export interface UseAsyncResourceOptions<T, E = string> {\\n /**\\n * Загрузчик. Получает `AbortSignal` — прокиньте его в `fetch`, чтобы отменённый\\n * запрос не висел в сети.\\n */\\n load: (signal: AbortSignal) => Promise<T>;\\n /**\\n * Ключ перезапуска: при изменении запускается новая загрузка (обычно id записи).\\n * Сравнивается по `Object.is`, поэтому передавайте примитив, а не свежий объект.\\n */\\n loadKey?: unknown;\\n /**\\n * `false` → загрузка не стартует, состояние `idle`. Режим создания новой записи.\\n * @default true\\n */\\n enabled?: boolean;\\n /**\\n * Побочный эффект после успеха — например `form.patchValue(data)`.\\n *\\n * Вызывается уже вне реактивного контекста (из колбэка промиса). Если внутри вы\\n * пишете и в значения формы, и в `updateComponentProps`, разнесите второе в\\n * `queueMicrotask` — иначе preact бросит «Cycle detected».\\n */\\n onSuccess?: (data: T) => void;\\n /** Побочный эффект после ошибки — логирование, тост. */\\n onError?: (error: E) => void;\\n /** Преобразование отказа промиса в отображаемую ошибку. @default {@link defaultToError} */\\n toError?: (e: unknown) => E;\\n}","summary":"Опции {@link useAsyncResource}.","description":"Опции {@link useAsyncResource}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncResource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"UseAsyncResourceReturn","kind":"interface","signature":"export interface UseAsyncResourceReturn<T, E = string> extends AsyncResourceState<T, E> {\\n /** Перезапустить загрузку вручную (кнопка «Повторить», внешний триггер). */\\n reload: () => void;\\n /** Прервать текущий запрос. Прерывание не считается ошибкой. */\\n abort: () => void;\\n}","summary":"Возвращаемое значение {@link useAsyncResource}.","description":"Возвращаемое значение {@link useAsyncResource}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/useAsyncResource.ts","entries":[".","./async-boundary"],"package":"@reformer/cdk"},{"name":"useFileUpload","kind":"function","signature":"export function useFileUpload(options: UseFileUploadOptions): UseFileUploadReturn","summary":"Headless-хук выбора и загрузки файлов: собственный список с семантикой «добавить» (нативный input каждый выбор ЗАМЕНЯЕТ `files` — поэтому input очищается после каждого change), отбор кандидатов (accept/размер/количество/дубликаты), drag-and-drop, paste, опциональная immediate-загрузка через инжектир","description":"Headless-хук выбора и загрузки файлов: собственный список с семантикой «добавить»\\n(нативный input каждый выбор ЗАМЕНЯЕТ `files` — поэтому input очищается после\\nкаждого change), отбор кандидатов (accept/размер/количество/дубликаты), drag-and-drop,\\npaste, опциональная immediate-загрузка через инжектируемый `uploader` и prop-getters\\nдля всех частей разметки.\\n\\nИспользуется самим `FileUpload.Root`, но пригоден и отдельно, когда compound-дерево\\nизбыточно.","params":[["options","- См. {@link UseFileUploadOptions}."]],"returns":"Состояние, действия и prop-getters — {@link UseFileUploadReturn}.","example":"Ручная разметка без compound-дерева\\n```tsx\\nimport { useFileUpload } from \'@reformer/cdk/file-upload\';\\n\\nfunction Uploader({ value, onChange }: Props) {\\nconst f = useFileUpload({ value, onChange, accept: \'image/*\', multiple: true });\\nreturn (\\n<div {...f.getRootProps()}>\\n<input {...f.getHiddenInputProps()} />\\n<div {...f.getDropzoneProps()} aria-label=\\"Загрузка изображений\\">\\nПеретащите файлы или нажмите\\n</div>\\n<ul {...f.getItemGroupProps()}>\\n{f.items.map((item) => (\\n <li key={item.key} {...f.getItemProps(item)}>\\n {item.file?.name}\\n <button {...f.getItemDeleteTriggerProps(item)}>×</button>\\n </li>\\n))}\\n</ul>\\n<div {...f.getLiveRegionProps()}>{f.liveMessage}</div>\\n</div>\\n);\\n}\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/useFileUpload.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"useFileUploadContext","kind":"function","signature":"export function useFileUploadContext(): FileUploadContextValue","summary":"Хук доступа к контексту `FileUpload`.","description":"Хук доступа к контексту `FileUpload`. Бросает исключение вне `FileUpload.Root`.","params":[],"returns":"Текущее {@link FileUploadContextValue}.","example":"Своя кнопка очистки вне слотов\\n```tsx\\nimport { useFileUploadContext } from \'@reformer/cdk/file-upload\';\\n\\nfunction ToolbarClear() {\\nconst { items, clear } = useFileUploadContext();\\nif (items.length === 0) return null;\\nreturn <button onClick={clear}>Очистить ({items.length})</button>;\\n}\\n```","examplesCount":1,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"useFileUploadItemContext","kind":"function","signature":"export function useFileUploadItemContext(): FileUploadItemContextValue","summary":"Хук доступа к per-item контексту (внутри `FileUpload.Item`).","description":"Хук доступа к per-item контексту (внутри `FileUpload.Item`).","params":[],"returns":"Текущий {@link FileUploadItemContextValue}.","examplesCount":0,"sourcePath":"src/components/file-upload/FileUploadContext.tsx","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"UseFileUploadOptions","kind":"interface","signature":"export interface UseFileUploadOptions {\\n // ── seam-контракт поля (controlled) ──\\n /** Текущее значение поля. */\\n value?: FileUploadValue;\\n /** Эмит нового значения (value-based). */\\n onChange?: (value: FileUploadValue) => void;\\n /** Пометить поле touched (обычно после закрытия пикера/blur зоны). */\\n onBlur?: () => void;\\n /** Поле недоступно: пикер не открывается, drop/paste игнорируются. */\\n disabled?: boolean;\\n // ── отбор файлов ──\\n /**\\n * Допустимые типы в синтаксисе нативного `accept` (`\'image/*,.pdf\'`). Пробрасывается\\n * в hidden input и применяется к drag-and-drop/paste через собственный матчер —\\n * нативный `accept` на drop не действует.\\n */\\n accept?: string;\\n /**\\n * Разрешить несколько файлов. При `false` новая селекция ЗАМЕНЯЕТ текущую,\\n * лимит файлов — 1.\\n * @default false\\n */\\n multiple?: boolean;\\n /** Максимум файлов в списке (действует при `multiple`). */\\n maxFiles?: number;\\n /** Максимальный размер одного файла, байты. */\\n maxFileSize?: number;\\n /** Минимальный размер одного файла, байты (например `1` — отсев пустых). */\\n minFileSize?: number;\\n /** Максимальный суммарный размер всех файлов, байты. */\\n maxTotalFileSize?: number;\\n /**\\n * Отклонять дубликаты (совпадение `name` + `size` с уже выбранным).\\n * @default true\\n */\\n preventDuplicates?: boolean;\\n /** Кастомная валидация файла при отборе. `null` — файл принят. */\\n validate?: (file: File, ctx: { existing: FileUploadItem[] }) => FileError[] | null;\\n // ── каналы ввода ──\\n /**\\n * Принимать drag-and-drop на зоне.\\n * @default true\\n */\\n allowDrop?: boolean;\\n /**\\n * Принимать файлы из буфера обмена (paste на сфокусированной зоне).\\n * @default false\\n */\\n allowPaste?: boolean;\\n /** Источник камеры для мобильного пикера (пробрасывается в hidden input). */\\n capture?: \'user\' | \'environment\';\\n // ── uploader-режим ──\\n /**\\n * Загрузчик. Задан — компонент работает в immediate-режиме: файлы уходят на сервер\\n * при выборе, значением поля становятся {@link RemoteFileRef}. Не задан — deferred:\\n * значение поля `File[]`, сеть — забота консумента при submit.\\n */\\n uploader?: FileUploadUploader;\\n /**\\n * Автоматически запускать загрузку принятых файлов (при заданном `uploader`).\\n * @default true\\n */\\n autoUpload?: boolean;\\n // ── события ──\\n /** Любое изменение внутреннего списка (включая прогресс и смену статусов). */\\n onFilesChange?: (items: FileUploadItem[]) => void;\\n /** Файлы приняты отбором (до загрузки). */\\n onAccept?: (files: File[]) => void;\\n /** Файлы отклонены отбором. */\\n onReject?: (rejections: FileRejection[]) => void;\\n /** Файл успешно загружен (uploader-режим). */\\n onUploadSuccess?: (item: Extract<FileUploadItem, { status: \'uploaded\' }>) => void;\\n /** Загрузка файла упала (uploader-режим). */\\n onUploadError?: (item: Extract<FileUploadItem, { status: \'error\' }>) => void;\\n /** Явный префикс для генерируемых id (a11y-связки). */\\n id?: string;\\n}","summary":"Опции {@link useFileUpload}.","description":"Опции {@link useFileUpload}. Совпадают с props `FileUpload.Root`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/types.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"UseFileUploadReturn","kind":"interface","signature":"export interface UseFileUploadReturn {\\n /** Текущий список файлов (все статусы). */\\n items: FileUploadItem[];\\n /** Отклонённые последним отбором. */\\n rejections: FileRejection[];\\n /** Файл тащат над зоной (drag-counter — вложенные элементы не «мигают»). */\\n dragging: boolean;\\n /** Дроп-зона в фокусе. */\\n focused: boolean;\\n disabled: boolean;\\n /** Лимит файлов достигнут (триггеры можно дизейблить). */\\n maxFilesReached: boolean;\\n /** Есть незавершённые загрузки (блокировка submit). */\\n uploading: boolean;\\n /** Сообщение для aria-live региона (обновляется на выбор/загрузку/ошибки). */\\n liveMessage: string;\\n ids: FileUploadIds;\\n\\n openFilePicker: () => void;\\n addFiles: (files: File[]) => void;\\n removeItem: (key: string) => void;\\n clear: () => void;\\n retry: (key: string) => void;\\n abort: (key?: string) => void;\\n /** Сфокусировать hidden input («подсветить невалидное поле»). */\\n focus: () => void;\\n /**\\n * Managed object URL превью: создаётся лениво, revoke при удалении элемента и\\n * unmount. Для `uploaded` без локального `file` возвращает `remote.url`.\\n */\\n getPreviewUrl: (key: string) => string | null;\\n\\n getRootProps: () => FileUploadRootPropGetters;\\n getDropzoneProps: () => FileUploadDropzonePropGetters;\\n getTriggerProps: () => {\\n type: \'button\';\\n disabled: boolean;\\n onClick: () => void;\\n };\\n getHiddenInputProps: () => Record<string, unknown> & { ref: Ref<HTMLInputElement> };\\n getItemGroupProps: () => { role: \'list\' };\\n getItemProps: (item: FileUploadItem) => { role: \'listitem\'; \'data-status\': string };\\n getItemDeleteTriggerProps: (item: FileUploadItem) => {\\n type: \'button\';\\n \'aria-label\': string;\\n disabled: boolean;\\n onClick: () => void;\\n };\\n getItemRetryTriggerProps: (item: FileUploadItem) => {\\n type: \'button\';\\n \'aria-label\': string;\\n onClick: () => void;\\n };\\n getClearTriggerProps: () => { type: \'button\'; disabled: boolean; onClick: () => void };\\n getLiveRegionProps: () => {\\n id: string;\\n role: \'status\';\\n \'aria-live\': \'polite\';\\n style: CSSProperties;\\n };\\n}","summary":"Возвращаемое значение {@link useFileUpload}.","description":"Возвращаемое значение {@link useFileUpload}.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/useFileUpload.ts","entries":[".","./file-upload"],"package":"@reformer/cdk"},{"name":"useFormArray","kind":"function","signature":"export function useFormArray<T extends object>(\\n control: FormArrayControl<T>\\n): UseFormArrayReturn<T>","summary":"Headless hook for managing form arrays Provides reactive state and actions for form array manipulation without any UI - perfect for building custom array interfaces.","description":"Headless hook for managing form arrays\\n\\nProvides reactive state and actions for form array manipulation\\nwithout any UI - perfect for building custom array interfaces.","params":[],"example":"Basic usage\\n```tsx\\nfunction PropertyList() {\\nconst { items, add, isEmpty } = useFormArray(form.properties);\\n\\nreturn (\\n<div>\\n{items.map(({ control, index, remove, id }) => (\\n<div key={id}>\\n <span>Property #{index + 1}</span>\\n <button onClick={remove}>Remove</button>\\n <PropertyForm control={control} />\\n</div>\\n))}\\n{isEmpty && <p>No properties added</p>}\\n<button onClick={() => add()}>Add Property</button>\\n</div>\\n);\\n}\\n```","examplesCount":3,"topics":["overview","form-array","recipes","troubleshooting"],"sourcePath":"src/components/form-array/useFormArray.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"useFormArrayContext","kind":"function","signature":"export function useFormArrayContext<\\n T extends object = Record<string, unknown>,\\n>(): FormArrayContextValue<T>","summary":"Хук для доступа к контексту `FormArray`.","description":"Хук для доступа к контексту `FormArray`. Бросает исключение, если вызван вне\\n`FormArray.Root` или эквивалентного провайдера.","params":[],"returns":"Текущий {@link FormArrayContextValue}.","example":"Кастомный AddButton с predefined значением\\n```tsx\\nimport { useFormArrayContext } from \'@reformer/cdk/form-array\';\\n\\nfunction AddDraftButton() {\\nconst { add } = useFormArrayContext<Item>();\\nreturn (\\n<button onClick={() => add({ status: \'draft\', createdAt: Date.now() })}>\\n+ Add Draft\\n</button>\\n);\\n}\\n```","examplesCount":2,"topics":["recipes","troubleshooting"],"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"useFormArrayItemContext","kind":"function","signature":"export function useFormArrayItemContext<\\n T extends object = Record<string, unknown>,\\n>(): FormArrayItemContextValue<T>","summary":"Хук для доступа к контексту текущего элемента внутри `FormArray.List`.","description":"Хук для доступа к контексту текущего элемента внутри `FormArray.List`.","params":[],"returns":"Текущий {@link FormArrayItemContextValue} (`control`, `index`, `id`, `remove`,\\n`moveUp`/`moveDown`, `canMoveUp`/`canMoveDown`).","example":"Кнопка удаления текущего элемента\\n```tsx\\nimport { useFormArrayItemContext } from \'@reformer/cdk/form-array\';\\n\\nfunction ItemRemoveButton() {\\nconst { remove } = useFormArrayItemContext();\\nreturn <button onClick={remove}>×</button>;\\n}\\n```","examplesCount":2,"topics":["recipes"],"sourcePath":"src/components/form-array/FormArrayContext.tsx","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"UseFormArrayReturn","kind":"interface","signature":"export interface UseFormArrayReturn<T extends object> {\\n /** Array of items with their controls and actions */\\n items: FormArrayItem<T>[];\\n /** Current number of items in the array */\\n length: number;\\n /** Whether the array is empty */\\n isEmpty: boolean;\\n /** Add a new item to the end of the array */\\n add: (value?: Partial<T>) => void;\\n /** Remove all items from the array */\\n clear: () => void;\\n /** Insert a new item at a specific index */\\n insert: (index: number, value?: Partial<T>) => void;\\n /** Remove an item by index (symmetric with insert-by-index) */\\n removeAt: (index: number) => void;\\n /** Move an item from one index to another (reorder, state preserved) */\\n move: (from: number, to: number) => void;\\n /** Swap two items by index (reorder, state preserved) */\\n swap: (a: number, b: number) => void;\\n /** Get item control at a specific index */\\n at: (index: number) => FormProxy<T> | undefined;\\n /** Array-level validation errors (e.g. `minItems`) */\\n errors: ValidationError[];\\n /** Whether the array (and all its items) is valid */\\n valid: boolean;\\n /** Whether the array (or any item) is invalid */\\n invalid: boolean;\\n}","summary":"Return type for useFormArray hook","description":"Return type for useFormArray hook","params":[],"examplesCount":0,"topics":["form-array"],"sourcePath":"src/components/form-array/useFormArray.ts","entries":[".","./form-array"],"package":"@reformer/cdk"},{"name":"useFormField","kind":"function","signature":"export function useFormField<T extends FormValue>(\\n control: FieldNode<T>,\\n id?: string\\n): UseFormFieldReturn<T>","summary":"Primary hook for building accessible form fields.","description":"Primary hook for building accessible form fields.\\n\\nReturns partitioned prop collections and structured state that you can spread\\ndirectly onto your own elements. No prescribed DOM structure.","params":[],"example":"Basic usage\\n```tsx\\nfunction EmailField({ control }: { control: FieldNode<string> }) {\\nconst { labelProps, controlProps, errorProps, state } = useFormField(control);\\n\\nreturn (\\n<div>\\n<label {...labelProps}>{state.label}</label>\\n<input {...controlProps} type=\\"email\\" />\\n{state.shouldShowError && (\\n<p {...errorProps}>{state.error}</p>\\n)}\\n</div>\\n);\\n}\\n```","examplesCount":2,"topics":["overview","form-field"],"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"useFormFieldContext","kind":"function","signature":"export function useFormFieldContext<T extends FormValue = FormValue>(): FormFieldContextValue<T>","summary":"Хук для доступа к контексту `FormField`.","description":"Хук для доступа к контексту `FormField`. Бросает исключение, если вызван\\nвне `FormField.Root`.","params":[],"returns":"Текущий {@link FormFieldContextValue}.","example":"Счётчик символов рядом с label\\n```tsx\\nimport { useFormFieldContext } from \'@reformer/cdk/form-field\';\\n\\nfunction CharCount() {\\nconst { control } = useFormFieldContext<string>();\\nreturn <small>{control.value.length} chars</small>;\\n}\\n```","examplesCount":2,"topics":["form-field","troubleshooting"],"sourcePath":"src/components/form-field/FormFieldContext.tsx","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldControlProps","kind":"interface","signature":"export interface UseFormFieldControlProps {\\n id: string;\\n disabled: boolean;\\n \'aria-labelledby\': string;\\n \'aria-invalid\': true | undefined;\\n \'aria-errormessage\': string | undefined;\\n \'aria-required\': true | undefined;\\n /** Direct-value onChange compatible with ReFormer field components */\\n onChange: (value: unknown) => void;\\n onBlur: () => void;\\n}","summary":"Props to spread onto the interactive control element","description":"Props to spread onto the interactive control element","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldDescriptionProps","kind":"interface","signature":"export interface UseFormFieldDescriptionProps {\\n id: string;\\n}","summary":"Props to spread onto a description paragraph","description":"Props to spread onto a description paragraph","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldErrorProps","kind":"interface","signature":"export interface UseFormFieldErrorProps {\\n id: string;\\n role: \'alert\';\\n}","summary":"Props to spread onto an error paragraph","description":"Props to spread onto an error paragraph","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldLabelProps","kind":"interface","signature":"export interface UseFormFieldLabelProps {\\n id: string;\\n htmlFor: string;\\n}","summary":"Props to spread onto a <label> element","description":"Props to spread onto a <label> element","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldReturn","kind":"interface","signature":"export interface UseFormFieldReturn<T extends FormValue = FormValue> {\\n /** Spread onto <label> */\\n labelProps: UseFormFieldLabelProps;\\n /** Spread onto the interactive control; includes value */\\n controlProps: UseFormFieldControlProps & { value: T };\\n /** Spread onto the first error paragraph */\\n errorProps: UseFormFieldErrorProps;\\n /** Spread onto the description paragraph */\\n descriptionProps: UseFormFieldDescriptionProps;\\n /** Structured field state */\\n state: UseFormFieldState<T>;\\n /** Field actions */\\n actions: {\\n setValue: (value: T) => void;\\n markAsTouched: () => void;\\n markAsUntouched: () => void;\\n reset: (value?: T) => void;\\n };\\n /** Raw IDs for manual wiring (e.g. aria-describedby) */\\n ids: FormFieldIds;\\n}","summary":"Return type of useFormField hook","description":"Return type of useFormField hook","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"UseFormFieldState","kind":"interface","signature":"export interface UseFormFieldState<T extends FormValue = FormValue> {\\n value: T;\\n errors: ValidationError[];\\n /** First error message, only set when shouldShowError is true */\\n error: string | undefined;\\n isPending: boolean;\\n isDisabled: boolean;\\n isValid: boolean;\\n isInvalid: boolean;\\n isTouched: boolean;\\n shouldShowError: boolean;\\n label: string | undefined;\\n required: boolean;\\n /** Full componentProps bag from FieldNode config */\\n componentProps: Record<string, unknown>;\\n}","summary":"Field state returned by useFormField","description":"Field state returned by useFormField","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/useFormField.ts","entries":[".","./form-field"],"package":"@reformer/cdk"},{"name":"useFormWizard","kind":"function","signature":"export function useFormWizard<T extends Record<string, any>>(): FormWizardContextValue<T>","summary":"Хук для доступа к контексту {@link FormWizard} из любого потомка.","description":"Хук для доступа к контексту {@link FormWizard} из любого потомка.\\n\\nВозвращает текущее состояние мастера (`currentStep`, `totalSteps`,\\n`completedSteps`, `isFirstStep`, `isLastStep`, `isValidating`, `isSubmitting`,\\n`form`), методы навигации (`goToNextStep`, `goToPreviousStep`, `goToStep`) и\\n`submit` — отправку с прогоном `config.validateAll` (`null`, если форма не прошла).\\nБросает исключение, если вызван вне `<FormWizard>`.\\n\\nДля внешнего управления (вне дерева Wizard) используйте\\n{@link FormWizardHandle} через `useRef`.","params":[],"returns":"Текущий {@link FormWizardContextValue}.","example":"Минимальное использование внутри custom-step\\n```tsx\\nfunction MyStepComponent() {\\nconst { currentStep, isLastStep } = useFormWizard();\\nreturn <p>Шаг {currentStep}{isLastStep && \' — последний\'}</p>;\\n}\\n```","examplesCount":2,"topics":["overview"],"sourcePath":"src/components/form-wizard/FormWizardContext.tsx","entries":[".","./form-wizard"],"package":"@reformer/cdk","usage":10},{"name":"useFormWizardActions","kind":"function","signature":"export function useFormWizardActions(): FormWizardActionsContextValue","summary":"Hook to access Actions context (onSubmit handler) Must be used within FormWizard.Actions component.","description":"Hook to access Actions context (onSubmit handler)\\n\\nMust be used within FormWizard.Actions component.\\nUsed internally by FormWizard.Submit.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/FormWizardActions.tsx","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"useList","kind":"function","signature":"export function useList<T extends object>(control: ListControl<T>): UseListReturn<T>","summary":"Headless-хук display-итерации массива модели — read-only брат {@link useFormArray}.","description":"Headless-хук display-итерации массива модели — read-only брат {@link useFormArray}.\\n\\nРеактивно подписывается на длину/значение массива и раскладывает его на элементы\\n`{ control, index, id }`. НЕ отдаёт `add`/`remove`/`move` — для display-списков (например,\\nсписок алертов), где элементы не редактируются, а появляются/исчезают через мутацию массива в\\nbehavior. Ключ `id` берётся из идентичности per-item контрола (`itemControl.id ?? index`), поэтому\\nreorder/фильтрация сохраняют состояние элементов.","params":[],"example":"```tsx\\nfunction AlertsView({ form }: { form: FormProxy<MyForm> }) {\\n const { items, isEmpty } = useList(form.alerts);\\n if (isEmpty) return null;\\n return (\\n <div className=\\"space-y-2\\">\\n {items.map(({ control, id }) => (\\n <Alert key={id} control={control} />\\n ))}\\n </div>\\n );\\n}\\n```","examplesCount":1,"sourcePath":"src/components/list/useList.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"useListContext","kind":"function","signature":"export function useListContext<T extends object = Record<string, unknown>>(): ListContextValue<T>","summary":"Доступ к контексту `List`.","description":"Доступ к контексту `List`. Бросает вне `List.Root`.","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"useListItemContext","kind":"function","signature":"export function useListItemContext<\\n T extends object = Record<string, unknown>,\\n>(): ListItemContextValue<T>","summary":"Доступ к контексту текущего элемента внутри `List.Items`.","description":"Доступ к контексту текущего элемента внутри `List.Items`. Бросает вне `List.Items`.","params":[],"examplesCount":0,"sourcePath":"src/components/list/ListContext.tsx","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"UseListReturn","kind":"interface","signature":"export interface UseListReturn<T extends object> {\\n /** Элементы списка с их контролами */\\n items: ListItem<T>[];\\n /** Текущая длина списка */\\n length: number;\\n /** Пустой ли список */\\n isEmpty: boolean;\\n}","summary":"Return type for {@link useList}.","description":"Return type for {@link useList}.","params":[],"examplesCount":0,"sourcePath":"src/components/list/useList.ts","entries":[".","./list"],"package":"@reformer/cdk"},{"name":"useValidationErrorResolver","kind":"function","signature":"export function useValidationErrorResolver(): ValidationErrorResolver","summary":"Возвращает текущий резолвер сообщений из контекста.","description":"Возвращает текущий резолвер сообщений из контекста. Если форма не обёрнута в\\n{@link ValidationMessagesProvider}, вернётся {@link defaultErrorResolver}. Используется\\nвнутри `useFormField` для преобразования {@link ValidationError} в отображаемую строку;\\nвызывайте напрямую, если строите собственный рендер ошибок.","params":[],"returns":"Активный {@link ValidationErrorResolver} (или дефолтный, если провайдера нет).","example":"Кастомный рендер ошибок с активным резолвером\\n```tsx\\nimport { useValidationErrorResolver } from \'@reformer/cdk\';\\nimport { useFormControl } from \'@reformer/core\';\\n\\nfunction FieldErrors({ control }: { control: FieldNode<string> }) {\\nconst resolve = useValidationErrorResolver();\\nconst { errors } = useFormControl(control);\\nreturn <>{errors.map((e) => <span key={e.code}>{resolve(e)}</span>)}</>;\\n}\\n```","examplesCount":1,"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk"},{"name":"useWizardStepValidation","kind":"function","signature":"export function useWizardStepValidation(config: StepValidationConfig): void","summary":"Армирует live-стратегию валидации (`strategy` из {@link defineSteps}) для ТЕКУЩЕГО шага мастера.","description":"Армирует live-стратегию валидации (`strategy` из {@link defineSteps}) для ТЕКУЩЕГО шага мастера.\\nЧитает `currentStep` из контекста {@link FormWizard}, собирает контроллер под под-схему шага и\\nснимает его при смене шага / размонтировании. Per-step gate («Далее») и submit (`validateAll`) не\\nзатрагиваются — это отдельный, живой слой поверх них.\\n\\nNo-op, если в `defineSteps` не задана `strategy` (или `\'submit\'`) либо у шага нет правил.","params":[],"example":"```tsx\\nconst config = defineSteps<\'loan\' | \'confirm\', Root>(model, {\\n steps: { loan: step1, confirm: null },\\n strategy: \'blur\',\\n});\\n\\nfunction LoanStepBody() {\\n useWizardStepValidation(config); // живая валидация полей шага при blur\\n return <>{/* поля шага *\\\\/}</>;\\n}\\n```","examplesCount":1,"topics":["form-navigation"],"sourcePath":"src/components/form-wizard/use-wizard-step-validation.ts","entries":["./form-wizard"],"package":"@reformer/cdk"},{"name":"ValidationErrorResolver","kind":"type","signature":"export type ValidationErrorResolver = (error: ValidationError) => string;","summary":"Преобразует ошибку валидации в отображаемую строку.","description":"Преобразует ошибку валидации в отображаемую строку.","params":[],"examplesCount":0,"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk"},{"name":"ValidationMessagesProvider","kind":"function","signature":"export function ValidationMessagesProvider(props: {\\n resolver: ValidationErrorResolver;\\n children: ReactNode;\\n}): ReactNode","summary":"Провайдер резолвера сообщений валидации (i18n) для поддерева формы.","description":"Провайдер резолвера сообщений валидации (i18n) для поддерева формы. Все `useFormField` внутри\\nначинают отображать не `error.message`, а результат переданного `resolver`. Оберните форму\\nрезолвером из {@link createMessageResolver}, чтобы включить локализацию по кодам ошибок.","params":[],"example":"Локализация всей формы через таблицу сообщений\\n```tsx\\nimport { ValidationMessagesProvider, createMessageResolver } from \'@reformer/cdk\';\\n\\nconst ru = createMessageResolver({\\nrequired: () => \'Обязательное поле\',\\nemail: () => \'Введите корректный email\',\\nminLength: (p) => `Минимум ${p?.minLength} символов`,\\n});\\n\\n<ValidationMessagesProvider resolver={ru}>\\n<MyForm />\\n</ValidationMessagesProvider>\\n```","examplesCount":1,"related":["createMessageResolver","useValidationErrorResolver"],"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk","usage":23},{"name":"ValidationMessageTable","kind":"type","signature":"export type ValidationMessageTable = Record<string, (params?: Record<string, unknown>) => string>;","summary":"Таблица `code → (params) => message`.","description":"Таблица `code → (params) => message`.","params":[],"examplesCount":0,"sourcePath":"src/validation/error-resolver.tsx","entries":["."],"package":"@reformer/cdk"},{"name":"WizardStepsConfig","kind":"interface","signature":"export interface WizardStepsConfig<Sel extends string> extends FormWizardConfig {\\n /** Валидация шага по номеру (1-based) — defineSteps всегда её возвращает (в базе она опциональна). */\\n validateStep: (step: number) => Promise<boolean>;\\n /** Полная валидация (submit) — всегда возвращается. */\\n validateAll: () => Promise<boolean>;\\n /** Селекторы шагов по порядку (индекс = `step - 1`). Для селекторной адресации/отладки. */\\n stepSelectors: Sel[];\\n /**\\n * Контроллер live-стратегии для под-схемы шага (1-based) — для {@link useWizardStepValidation}.\\n * Возвращает `null`, если live-стратегия не задана (`strategy` отсутствует / `\'submit\'`) или у\\n * шага нет правил. Тип {@link FormValidationController} не зависит от `T`.\\n */\\n createStepController: (step: number) => FormValidationController | null;\\n}","summary":"Результат {@link defineSteps}: {@link FormWizardConfig} + упорядоченный список селекторов шагов.","description":"Результат {@link defineSteps}: {@link FormWizardConfig} + упорядоченный список селекторов шагов.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/define-steps.ts","entries":[".","./form-wizard"],"package":"@reformer/cdk"}]},"@reformer/ui-kit":{"schemaVersion":1,"package":"@reformer/ui-kit","version":"6.0.0","topics":[{"id":"overview","file":"01-overview.md","title":"Overview","purpose":"`@reformer/ui-kit` — это набор готовых стилизованных React-компонентов для форм на [`@reformer/core`](../../../reformer/) и [`@reformer/cdk`](../../../reformer-cdk/). Под капотом — Tailwind CSS и Radix UI; интерфейс компонентов спроектирован под контракт `value` / `onChange` / `onBlur` `FieldNode<T>`, поэтому подключение к форме сводится к `<FormField control={form.email} />` или к регистрации компонента в `RenderSchema` рендерера.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-text-fields.md](02-text-fields.md) — `Input`, `InputMask`, `InputPassword`, `Textarea`.","[03-choice-fields.md](03-choice-fields.md) — `Checkbox`, `RadioGroup`, `Select`, мультивыборы, варианты дерева у `Combobox`.","[04-layout-and-buttons.md](04-layout-and-buttons.md) — `Button`, `AsyncBoundary`, `Tree`, `ExampleCard`, `cn`.","[05-form-field-integration.md](05-form-field-integration.md) — `FormField` standalone и как `fieldWrapper`.","[06-troubleshooting.md](06-troubleshooting.md) — типичные проблемы и решения.","[11-form-layout.md](11-form-layout.md) — отступы, сетка полей, группировка и секции."],"sections":[{"heading":"Installation","slug":"installation"},{"heading":"Import Patterns","slug":"import-patterns"},{"heading":"Quick Start","slug":"quick-start"},{"heading":"Две линейки: примитив и `*Field`","slug":"dve-lineyki-primitiv-i-field"},{"heading":"Components","slug":"components"},{"heading":"See also","slug":"see-also"}],"terms":[["reformer",28],["form",21],["layout",21],["fields",20],["react",14],["для",13],["email",13],["import",13],["field",13],["kit",12],["formfield",12],["input",12],["text",12],["model",12],["and",12],["buttons",12],["from",11],["choice",10],["value",9],["button",9],["select",9],["cdk",8],["tree",8],["поле",8],["core",7],["const",7],["без",6],["label",6],["checkbox",6],["inputfield",6],["password",6],["примитив",6],["компонентов",5],["tailwind",5],["error",5],["radiogroup",5],["формы",5],["troubleshooting",5],["control",4],["компоненты",4],["examplecard",4],["asyncboundary",4],["только",4],["зависимости",4],["combobox",4],["inputmask",4],["inputpassword",4],["textarea",4],["selectfield",4],["createform",4],["schema",4],["validate",4],["inputpasswordfield",4],["registrationform",4],["модели",4],["component",4],["integration",4],["форм",3],["radix",3],["onchange",3],["или",3],["pending",3],["destructive",3],["peer",3],["renderer",3],["table",3],["message",3],["typescript",3],["полей",3],["createmodel",3],["валидация",3],["definevalidationschema",3],["validatemodel",3],["required",3],["type",3],["componentprops",3],["testid",3],["return",3],["onsubmit",3],["сам",3],["форму",3],["выбор",3],["checkboxfield",3],["options",3],["это",2],["под",2],["css",2],["контракт",2],["поэтому",2],["форме",2],["компонента",2],["renderschema",2],["headless",2],["имеет",2],["стили",2],["utility",2],["классы",2],["через",2],["aria",2],["вариантами",2],["playground",2],["если",2],["пакет",2],["npm",2],["быть",2],["проекте",2],["json",2],["пакета",2],["нужен",2],["recharts",2],["эти",2],["subpath",2],["поставить",2],["вариант",2],["calendar",2],["picker",2],["date",2],["carousel",2],["otp",2],["resizable",2],["sonner",2],["shadcn",2],["все",2],["box",2],["section",2],["collapsible",2],["shaking",2],["sub",2],["форма",2],["схема",2],["usememo",2],["validation",2],["minlength",2],["validators",2],["string",2],["схеме",2],["registrationvalidation",2],["обязателен",2],["пароль",2],["модель",2],["ноды",2],["async",2],["submit",2],["версия",2],["checked",2],["что",2],["cmp",2],["variant",2],["дефолт",2],["inputmaskfield",2],["radiogroupfield",2],["textareafield",2],["comboboxfield",2],["иерархии",2],["версии",2],["number",2],["варианты",2],["loading",2],["карточка",2],["классов",2],["сетка",2]]},{"id":"text-fields","file":"02-text-fields.md","title":"Text fields","purpose":"Текстовые поля ввода: `Input`, `InputMask`, `InputPassword`, `Textarea`. Все четыре компонента следуют единому контракту:","keyConcepts":[],"api":"```typescript\\ninterface InputProps {\\n className?: string;\\n value?: string | number | null;\\n onChange?: (value: string | number | null) => void;\\n onBlur?: () => void;\\n type?: \'text\' | \'email\' | \'number\' | \'tel\' | \'url\' | \'password\';\\n placeholder?: string;\\n disabled?: boolean;\\n // плюс все нативные props кроме value/onChange:\\n // min, max, step, autoComplete, name, id, aria-*, data-*\\n}\\n```\\n\\n| Prop | Тип | Default | Описание |\\n| ------------- | ------------------------------------------- | --------------- | -------------------------------------------------------------------------- |\\n| `value` | `string \\\\| number \\\\| null` | `\'\'` рендерится | Текущее значение. `null`/`undefined` → пустое поле. |\\n| `onChange` | `(value: string \\\\| number \\\\| null) => void` | — | Вызывается при вводе. Пустая строка → `null`. Для `type=\'number\'` — число. |\\n| `onBlur` | `() => void` | — | Срабатывает при потере фокуса. |\\n| `type` | union | `\'text\'` | HTML `type`. Для `\'number\'` включается числовой парсинг. |\\n| `placeholder` | `string` | — | Подсказка. |\\n| `disabled` | `boolean` | `false` | Блокирует ввод. **Seam-проп:** внутри формы приходит из состояния узла (`control.disable()`), а не из `componentProps` — см. ниже. |\\n\\n> **`disabled` внутри формы задаётся не пропом.** Перечисленные выше `value`/`onChange`/`onBlur`/`disabled` — это\\n> контракт «сырого» компонента. Когда поле рендерится формой (`FormField`, renderer-react, renderer-json), их\\n> подставляет seam: `FormFieldControl` ставит `disabled` из состояния узла ПОСЛЕ спреда `componentProps`, поэтому\\n> `componentProps.disabled` затирается и не работает. Props-схемы field-компонентов его намеренно не объявляют —\\n> в JSON-DSL он вернёт `has unknown property \\"disabled\\"`. Управляйте через `control.disable()` / `control.enable()`.","patterns":[{"lang":"tsx","code":"import { InputField } from \'@reformer/ui-kit\';\\n\\n<InputField value={name} onChange={setName} placeholder=\\"Имя\\" />;"},{"lang":"tsx","code":"<InputField type=\\"number\\" value={age} onChange={setAge} min={0} placeholder=\\"Возраст\\" />"},{"lang":"tsx","code":"import { createModel, createForm } from \'@reformer/core\';\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, email } from \'@reformer/core/validators\';\\nimport { InputField, FormField } from \'@reformer/ui-kit\';\\n\\nconst model = createModel<{ email: string }>({ email: \'\' });\\nconst schema = {\\n children: [\\n {\\n value: model.$.email,\\n component: InputField,\\n componentProps: { type: \'email\', label: \'Email\', testId: \'email\' },\\n },\\n ],\\n};\\nconst validation = defineValidationSchema<{ email: string }>(({ model }) => {\\n validate(model.$.email, [required(), email()]);\\n});\\nconst form = createForm<{ email: string }>({ model, schema });\\n\\n// Через FormField значение/ошибки подцепляются автоматически:\\n<FormField control={form.email} testId=\\"email\\" />;"},{"lang":"tsx","code":"import { InputMaskField } from \'@reformer/ui-kit\';\\n\\n<InputMaskField value={phone} onChange={setPhone} mask=\\"+7 (999) 999-99-99\\" />;"},{"lang":"tsx","code":"<InputMaskField value={inn} onChange={setInn} mask=\\"9999999999\\" placeholder=\\"ИНН\\" />"},{"lang":"tsx","code":"<InputMaskField value={birthDate} onChange={setBirthDate} mask=\\"99.99.9999\\" />"},{"lang":"tsx","code":"import { InputPasswordField } from \'@reformer/ui-kit\';\\n\\n<InputPasswordField value={password} onChange={setPassword} placeholder=\\"Пароль\\" />;"},{"lang":"tsx","code":"<InputPasswordField value={password} onChange={setPassword} showToggle={false} />"},{"lang":"tsx","code":"<InputPasswordField value={form.password.value} onChange={form.password.setValue} />\\n<InputPasswordField\\n value={form.passwordConfirm.value}\\n onChange={form.passwordConfirm.setValue}\\n placeholder=\\"Повторите пароль\\"\\n/>"},{"lang":"tsx","code":"import { TextareaField } from \'@reformer/ui-kit\';\\n\\n<TextareaField\\n value={comment}\\n onChange={setComment}\\n rows={5}\\n maxLength={500}\\n placeholder=\\"Опишите проблему\\"\\n/>;"},{"lang":"tsx","code":"<TextareaField value={address} onChange={setAddress} rows={3} placeholder=\\"Адрес\\" />"}],"antiPatterns":[{"note":"- Передавать `value: number` для `type=\'text\'` — компонент сделает\\n `String(value)`, но при следующем `onChange` значение придёт строкой и\\n типы в форме разойдутся.\\n- Опускать `min={0}` и ожидать, что отрицательные числа отсекутся сами — нет,\\n без `min` отрицательные значения проходят.\\n- Перехватывать `onChange={(e) => …}` напрямую (как у нативного `<input>`).\\n `InputField` отдаёт сразу значение, а не event.\\n- **Ставить в форму примитив `Input` вместо `InputField`.** Примитив — нативный\\n `<input>`: его `onChange` отдаёт `SyntheticEvent`, и в модель уедет объект события,\\n а не строка. Ни TypeScript, ни `validate_form` этого не поймают — поле выглядит\\n рабочим. То же для `Textarea`/`TextareaField`, `InputMask`/`InputMaskField`."},{"note":"- **Рассчитывать, что маска отформатирует ввод.** `InputMask` ввод НЕ трансформирует:\\n `onChange` отдаёт `event.target.value` как есть, а `mask` используется только как\\n `placeholder`-подсказка. Наберёт пользователь `+7 (999) …` — столько и уедет в модель;\\n наберёт `9999999999` — уедет без литералов. Если формат обязателен, проверяйте его\\n правилом валидации, а нормализуйте в behavior `transformValue` или при сабмите.\\n- Поэтому регулярка валидации не должна требовать литералов, если только вы не приводите\\n значение к формату сами: `/^\\\\d{10}$/` пройдёт, а `/^\\\\+7 \\\\(\\\\d{3}\\\\)…/` — нет.\\n- Использовать `mask` для сложных правил (валидация диапазонов, контрольные\\n суммы) — `InputMask` только направляет ввод, не валидирует. Валидацию вешать\\n через `validate(model.$.x, [...])` в validation-схеме (запуск `validateModel`)."},{"note":"- Использовать `<InputField type=\\"password\\">` вместо `InputPassword`, если нужен\\n переключатель видимости — `Input` его не имеет.\\n- Хранить пароль с побочными состояниями (`maskedValue`, `realValue`). Компонент\\n всегда отдаёт raw-строку через `onChange`; маскирование — задача браузера."},{"note":"- Передавать `rows={1}` — для одной строки используйте `Input`. Textarea не\\n имеет логики авто-роста.\\n- Полагаться на `maxLength` как валидатор: это soft-лимит на ввод; для бизнес-\\n правил (например, `длина <= 500 на русском, <= 1000 на английском`) ставить\\n `validators` в лист схемы (`{ value: model.$.field, component, validators }`)."}],"examples":[],"troubleshooting":[],"seeAlso":["[03-choice-fields.md](03-choice-fields.md) — Select, CheckboxField, RadioGroupField.","[05-form-field-integration.md](05-form-field-integration.md) — как все эти поля автоматически подключаются через `FormField`.","[06-troubleshooting.md](06-troubleshooting.md) — «number возвращает строку», «mask пропускает символы», «password toggle не появляется»."],"sections":[{"heading":"Components","slug":"components-2"},{"heading":"Input","slug":"input"},{"heading":"InputMask","slug":"inputmask"},{"heading":"InputPassword","slug":"inputpassword"},{"heading":"Textarea","slug":"textarea"},{"heading":"See also","slug":"see-also-2"}],"terms":[["value",38],["string",29],["onchange",26],["number",20],["null",17],["email",17],["placeholder",15],["для",12],["tsx",11],["type",10],["password",10],["void",10],["disabled",10],["mask",10],["input",9],["reformer",9],["from",9],["model",9],["поле",8],["patterns",8],["import",8],["inputfield",8],["form",8],["как",7],["onblur",7],["formfield",7],["через",7],["значение",7],["boolean",7],["default",7],["ввод",7],["inputmask",6],["kit",6],["rows",6],["min",6],["text",5],["textarea",5],["отдаёт",5],["только",5],["maxlength",5],["typescript",5],["тип",5],["при",5],["inputmaskfield",5],["inputpasswordfield",5],["поля",4],["inputpassword",4],["без",4],["renderer",4],["глаз",4],["api",4],["interface",4],["classname",4],["prop",4],["описание",4],["подсказка",4],["формы",4],["control",4],["componentprops",4],["field",4],["его",4],["common",4],["const",4],["anti",4],["textareafield",4],["если",4],["fields",3],["все",3],["строка",3],["используется",3],["это",3],["json",3],["seam",3],["event",3],["name",3],["цифра",3],["инн",3],["пароля",3],["адрес",3],["поэтому",3],["createmodel",3],["component",3],["createform",3],["schema",3],["definevalidationschema",3],["core",3],["validate",3],["validation",3],["validators",3],["уедет",3],["символы",3],["showtoggle",3],["видимости",3],["пароль",3],["четыре",2],["компонента",2],["пустая",2],["fieldadapter",2],["нужен",2],["эти",2],["react",2],["есть",2],["возвращает",2],["undefined",2],["выше",2],["when",2],["tel",2],["url",2],["умолчанию",2],["маска",2],["переключателем",2],["props",2],["рендерится",2],["вызывается",2],["html",2],["false",2],["внутри",2],["состояния",2],["узла",2],["disable",2],["когда",2],["схемы",2],["форме",2],["валидация",2],["уровне",2],["запуск",2],["validatemodel",2],["required",2],["testid",2],["автоматически",2],["передавать",2],["компонент",2],["что",2],["отрицательные",2],["сами",2],["нет",2],["ставить",2],["примитив",2],["вместо",2],["модель",2],["остальные",2],["литералы",2],["наберёт",2],["литералов",2],["валидации",2],["использовать",2],["правил",2],["true",2],["показывать",2],["setpassword",2],["setvalue",2],["passwordconfirm",2],["имеет",2],["строку",2],["resize",2],["choice",2],["integration",2],["troubleshooting",2]]},{"id":"choice-fields","file":"03-choice-fields.md","title":"Choice fields","purpose":"Поля выбора: `Checkbox`, `RadioGroup`, `Select` (+ 8 sub-компонентов из Radix). Контракт `value`/`onChange`/`onBlur` тот же, что у текстовых полей, но `value` бывает разных типов:","keyConcepts":["**Значение — `node.id`, а не подпись.** Подпись в триггере берётся из объявленного дерева, а","**`selectable` по умолчанию `\'leaf\'`** — в отличие от самого `Tree`, где умолчание `\'all\'`.","**Пустой выбор мульти — `null`, никогда `[]`** (тот же контракт и та же причина, что у","**Обязательность — только `required()`.** `minLength(1)` на пустом выборе делает ранний","**Одиночный закрывает поповер по выбору**, мульти — **нет**: набор файлов собирают одним","**Членство в мульти переключается щелчком по строке**, отметка — галочка справа. Чекбокса","**Поиск свой, не cmdk**: фильтрует само дерево, достраивая путь до совпадения. Видит только","**`maxItems` — подсказка интерфейса**, а не правило формы: по достижении потолка невыбранные","**Путь до выбранного раскрывается сам** — но только по объявленному `nodes`. У ленивого"],"api":"```typescript\\ninterface CheckboxProps {\\n className?: string;\\n value?: boolean;\\n onChange?: (value: boolean) => void;\\n onBlur?: () => void;\\n label?: string;\\n disabled?: boolean;\\n \'data-testid\'?: string;\\n}\\n```\\n\\n| Prop | Тип | Default | Описание |\\n| ---------- | -------------------------- | ------- | ------------------------------------------------------------------------ |\\n| `value` | `boolean` | `false` | Чекнут или нет. `undefined` → `false`. |\\n| `onChange` | `(value: boolean) => void` | — | Вызывается с `event.target.checked`. |\\n| `label` | `string` | — | Подпись справа от чекбокса. Если опущен — рендерится только сам чекбокс. |\\n| `disabled` | `boolean` | `false` | Блокирует переключение. |","patterns":[{"lang":"tsx","code":"import { CheckboxField } from \'@reformer/ui-kit\';\\n\\n<CheckboxField value={agree} onChange={setAgree} label=\\"Согласен с условиями\\" />;"},{"lang":"tsx","code":"<div className=\\"flex items-center gap-2\\">\\n <CheckboxField value={hasMortgage} onChange={setHasMortgage} />\\n <span>У меня уже есть ипотека</span>\\n</div>"},{"lang":"tsx","code":"import { createModel, createForm } from \'@reformer/core\';\\nimport { CheckboxField, FormField } from \'@reformer/ui-kit\';\\n\\nconst model = createModel<{ accept: boolean }>({ accept: false });\\nconst schema = {\\n children: [\\n { value: model.$.accept, component: CheckboxField, componentProps: { label: \'Принять\' } },\\n ],\\n};\\nconst form = createForm<{ accept: boolean }>({ model, schema });\\n\\n<FormField control={form.accept} testId=\\"accept\\" />;"},{"lang":"tsx","code":"import { RadioGroupField } from \'@reformer/ui-kit\';\\n\\nconst LOAN_TYPES = [\\n { value: \'consumer\', label: \'Потребительский\' },\\n { value: \'mortgage\', label: \'Ипотека\' },\\n { value: \'auto\', label: \'Авто\' },\\n];\\n\\n<RadioGroupField value={loanType} onChange={setLoanType} options={LOAN_TYPES} />;"},{"lang":"tsx","code":"<RadioGroupField\\n value={size}\\n onChange={setSize}\\n options={[\\n { value: \'s\', label: \'S\' },\\n { value: \'m\', label: \'M\' },\\n { value: \'l\', label: \'L\' },\\n ]}\\n className=\\"!flex-row gap-6\\"\\n/>"},{"lang":"tsx","code":"import { createModel, createForm } from \'@reformer/core\';\\n\\nconst model = createModel<{ loanType: string }>({ loanType: \'consumer\' });\\nconst schema = {\\n children: [\\n {\\n value: model.$.loanType,\\n component: RadioGroupField,\\n componentProps: { options: LOAN_TYPES },\\n },\\n ],\\n};\\nconst form = createForm<{ loanType: string }>({ model, schema });\\n\\n<FormField control={form.loanType} testId=\\"loan-type\\" />;"},{"lang":"tsx","code":"import { SelectField } from \'@reformer/ui-kit\';\\n\\n<SelectField\\n value={loanType}\\n onChange={setLoanType}\\n placeholder=\\"Тип кредита\\"\\n options={[\\n { value: \'consumer\', label: \'Потребительский\' },\\n { value: \'mortgage\', label: \'Ипотека\' },\\n ]}\\n/>;"},{"lang":"tsx","code":"import { SelectField, type ResourceConfig } from \'@reformer/ui-kit\';\\n\\nconst banksResource: ResourceConfig<string> = {\\n type: \'preload\',\\n load: async () => {\\n const res = await fetch(\'/api/banks\');\\n const banks: Array<{ id: number; name: string }> = await res.json();\\n return {\\n items: banks.map((b) => ({ id: b.id, value: String(b.id), label: b.name })),\\n totalCount: banks.length,\\n };\\n },\\n};\\n\\n<SelectField value={bankId} onChange={setBankId} resource={banksResource} />;"},{"lang":"tsx","code":"const usersResource: ResourceConfig<string> = {\\n type: \'partial\',\\n pageSize: 20,\\n load: async ({ search = \'\', page = 1, pageSize = 20 } = {}) => {\\n const res = await fetch(`/api/users?q=${search}&page=${page}&size=${pageSize}`);\\n const { rows, total }: { rows: Array<{ id: number; name: string }>; total: number } =\\n await res.json();\\n return {\\n items: rows.map((u) => ({ id: u.id, value: String(u.id), label: u.name })),\\n totalCount: total, // Select догружает страницы, пока items.length < totalCount\\n };\\n },\\n};\\n\\n<SelectField value={userId} onChange={setUserId} resource={usersResource} clearable />;"},{"lang":"tsx","code":"<SelectField\\n value={city}\\n onChange={setCity}\\n options={[\\n { value: \'msk\', label: \'Москва\', group: \'Россия\' },\\n { value: \'spb\', label: \'Санкт-Петербург\', group: \'Россия\' },\\n { value: \'minsk\', label: \'Минск\', group: \'Беларусь\' },\\n { value: \'kiev\', label: \'Киев\', group: \'Украина\' },\\n ]}\\n/>"},{"lang":"tsx","code":"<SelectField\\n value={status}\\n onChange={setStatus}\\n clearable\\n placeholder=\\"Любой\\"\\n options={[\\n { value: \'open\', label: \'Открыт\' },\\n { value: \'closed\', label: \'Закрыт\' },\\n ]}\\n/>"},{"lang":"tsx","code":"import { createModel, createForm } from \'@reformer/core\';\\n\\nconst model = createModel<{ city: string }>({ city: \'\' });\\nconst schema = {\\n children: [\\n {\\n value: model.$.city,\\n component: SelectField,\\n componentProps: {\\n placeholder: \'Город\',\\n options: [\\n { value: \'msk\', label: \'Москва\' },\\n { value: \'spb\', label: \'Санкт-Петербург\' },\\n ],\\n },\\n },\\n ],\\n};\\nconst form = createForm<{ city: string }>({ model, schema });\\n\\n<FormField control={form.city} testId=\\"city\\" />;"},{"lang":"tsx","code":"import { createModel, createForm } from \'@reformer/core\';\\nimport { FormField } from \'@reformer/ui-kit\';\\nimport { ComboboxTreeField } from \'@reformer/ui-kit/combobox\';\\nimport type { TreeNode } from \'@reformer/ui-kit\';\\n\\n// id — полный путь: два index.ts в разных каталогах обязаны различаться.\\nconst FILES: TreeNode[] = [\\n {\\n id: \'src\',\\n label: \'src\',\\n children: [\\n { id: \'src/index.ts\', label: \'index.ts\' },\\n { id: \'src/app.tsx\', label: \'app.tsx\' },\\n ],\\n },\\n { id: \'package.json\', label: \'package.json\' },\\n];\\n\\nconst model = createModel<{ entry: string | null }>({ entry: null });\\nconst schema = {\\n entry: {\\n value: model.$.entry,\\n component: ComboboxTreeField,\\n componentProps: {\\n label: \'Точка входа\',\\n nodes: FILES,\\n defaultExpandedIds: [\'src\'],\\n clearable: true,\\n testId: \'entry\',\\n },\\n },\\n};\\nconst form = createForm<{ entry: string | null }>({ model, schema });\\n\\n<FormField control={form.entry} testId=\\"entry\\" />;"},{"lang":"typescript","code":"import { ComboboxTreeMultiField } from \'@reformer/ui-kit/combobox\';\\nimport { defineValidationSchema, validate } from \'@reformer/core/validation\';\\nimport { required, maxLength } from \'@reformer/core/validators\';\\n\\ntype Form = { attachments: string[] | null };\\n\\nconst model = createModel<Form>({ attachments: null }); // не [] — иначе поля не будет\\nconst schema = {\\n attachments: {\\n value: model.signalAt(\'attachments\')!,\\n component: ComboboxTreeMultiField,\\n componentProps: {\\n label: \'Файлы заявки\',\\n // Уровень читается при первом раскрытии ветки; null — верхний уровень.\\n loadChildren: (node) => fs.list(node?.id ?? \'/\'),\\n maxItems: 5,\\n testId: \'attachments\',\\n },\\n },\\n};\\n\\nconst validation = defineValidationSchema<Form>(({ model }) => {\\n validate(model.signalAt(\'attachments\')!, [required(), maxLength(5)]);\\n});"}],"antiPatterns":[{"note":"- Передавать `value: \'yes\' | \'no\'` (строку) — `CheckboxField` ожидает `boolean`. Для\\n строкового выбора используйте `RadioGroupField` (два варианта) или `SelectField`.\\n- Делать `<CheckboxField checked={x} onChange={…}>` (как с нативным `<input\\ntype=\\"checkbox\\">`) — у field-версии пропа `checked` нет, нужно `value`.\\n- **Ставить в форму примитив `Checkbox` вместо `CheckboxField`.** У примитива всё\\n наоборот: он Radix-контрол с `checked`, и `value={true}` он проигнорирует —\\n чекбокс останется `aria-checked=\\"false\\"`, а `label`/`value` утекут в DOM-атрибуты.\\n То же для `RadioGroup`/`RadioGroupField` (примитив отрисуется пустым) и\\n `Select`/`SelectField`."},{"note":"- Передавать `options` с числовыми `value` — компонент ставит их в DOM-атрибут\\n `value`, который всегда строка, и `onChange` вернёт строку. Это рассинхронит\\n типы. Если нужны числа — конвертируй на уровне behavior `transformValue`.\\n- Динамически менять список `options` без пересоздания компонента — текущее\\n `value` может оказаться вне набора, и ничего не выбрано визуально.\\n- Ожидать, что `onBlur` сработает после клика на radio — он срабатывает на\\n `blur` нативного input, как обычно. Для пометки `touched` после взаимодействия\\n обычно достаточно `onChange`."},{"note":"- Передавать одновременно `options` и `resource` — `options` приоритетнее,\\n `resource.load` всё равно вызовется на маунт (лишний запрос). Выбирай один\\n источник.\\n- Опускать `value` (`undefined`) — Radix покажет placeholder, но сам компонент\\n всегда мапит `undefined` в пустую строку. Лучше явно `null`.\\n- Использовать `value: number` напрямую — `Select` приводит к строке внутри\\n (`String(value)`); `onChange` вернёт строку. В schema формы тип поля должен\\n быть `string` или `string | null`.\\n- Регистрировать `Select` без `placeholder` и ждать понятного UX —\\n пользователь увидит дефолт `\'Select an option...\'`. Для русскоязычных форм\\n это, как правило, нежелательно."},{"note":"- Начальное значение `[]` вместо `null` — поле молча исчезает (см. выше).\\n- Мутация массива на месте: `arr.push(x); onChange(arr)` — preact-сигнал бэйлится по `!==`, UI не\\n обновится, но поле уже станет `dirty`, и валидация прогонится по старому значению. `onChange`\\n обязан отдавать **новый** массив.\\n- `minFiles` / `maxFiles` на массиве строк — тихий no-op: они фильтруют значение до file-like и\\n получают пустой массив. Для количества — `minLength` / `maxLength`.\\n- `compute` / `copyFrom` / `transformValue` над мультивыбором — peek-guard сравнивает по ссылке,\\n поэтому новый массив на каждом прогоне даёт запись на каждом прогоне; пара взаимных `compute`\\n сходит в расходящийся цикл или в `Cycle detected`. Сравнивайте содержимое руками и выходите до\\n записи.\\n- `componentProps.disabled` для выключения отдельных опций — мёртв (враппер ставит `disabled`\\n после спреда `componentProps`). Выключить можно только контрол целиком (`control.disable()`).\\n- `NativeSelectMulti` на тач-устройствах — множественный выбор в нативном листбоксе там\\n практически недоступен и не имеет аффорданса «можно несколько». Берите `ToggleGroupMulti` или\\n `SelectMulti`.\\n- `placeholder` у `NativeSelectMulti` — его нет намеренно: в multiple-листбоксе `<option value=\\"\\">`\\n становится выбираемым мусорным пунктом."},{"note":"- Начальное значение мульти `[]` вместо `null` — поле молча исчезает; симптомы разобраны в\\n [06-troubleshooting.md](06-troubleshooting.md), пункт 12.\\n- `minLength(1)` вместо `required()` для обязательности — пустой выбор приходит как `null`, и\\n правило выходит раньше проверки.\\n- Одинаковые `node.id` у разных узлов (имя файла вместо полного пути) — раскрытие, выделение и\\n отметка адресуются одним и тем же ключом, поэтому две строки начинают вести себя как одна.\\n- Ждать, что поиск найдёт файл в непрочитанном каталоге. Фильтр не ходит за уровнями: ради\\n подсветки одной строки пришлось бы обойти весь источник. Нужен сквозной поиск — ищите на\\n сервере и подавайте `nodes` уже отфильтрованными.\\n- Полагаться на `maxItems` как на валидацию — это только гашение строк в интерфейсе, форма о нём\\n ничего не знает.\\n- Импортировать `ComboboxTree*` из `\'@reformer/ui-kit\'` — их там нет, `combobox` живёт только в\\n своём subpath.\\n- Ставить в схему примитив `ComboboxTree` / `ComboboxTreeMulti` вместо `*Field`-версии —\\n value-seam остаётся неподключённым, поле рисуется и не реагирует на выбор."}],"examples":[],"troubleshooting":[],"seeAlso":["[04-layout-and-buttons.md](04-layout-and-buttons.md) — сам `Tree`: узлы, ленивое чтение уровней, виртуализация.","[10-imperative-handles.md](10-imperative-handles.md) — императивные handle мультивыборов (open/close/clear).","[02-text-fields.md](02-text-fields.md) — `Input`, `InputMask`, `InputPassword`, `Textarea`.","[05-form-field-integration.md](05-form-field-integration.md) — `FormField` распознаёт `Checkbox` и не дублирует label.","[06-troubleshooting.md](06-troubleshooting.md) — «Select не показывает options», «options vs resource», «onBlur не срабатывает на Select/RadioGroup»."],"sections":[{"heading":"Checkbox","slug":"checkbox"},{"heading":"RadioGroup","slug":"radiogroup"},{"heading":"Select","slug":"select"},{"heading":"Multi-select","slug":"multi-select"},{"heading":"Combobox: варианты дерева","slug":"combobox-varianty-dereva"},{"heading":"See also","slug":"see-also-3"}],"terms":[["value",81],["string",53],["label",41],["null",40],["const",27],["onchange",25],["model",24],["options",23],["reformer",22],["import",21],["from",21],["select",18],["boolean",18],["tsx",15],["form",15],["type",14],["kit",14],["для",13],["только",12],["createmodel",12],["resource",12],["schema",11],["group",11],["partial",11],["при",10],["void",10],["false",10],["patterns",10],["createform",10],["selectfield",10],["number",10],["значение",10],["что",9],["clearable",9],["testid",9],["нет",9],["без",9],["formfield",9],["поиск",9],["placeholder",9],["выбор",9],["поля",8],["component",8],["typescript",8],["disabled",8],["checkboxfield",8],["core",8],["componentprops",8],["как",8],["load",8],["tags",8],["combobox",8],["entry",8],["checkbox",7],["onblur",7],["или",7],["формы",7],["это",7],["loantype",7],["после",7],["массив",7],["поле",7],["city",7],["required",7],["maxlength",7],["signalat",7],["radix",6],["classname",6],["тип",6],["сам",6],["accept",6],["radiogroupfield",6],["field",6],["вместо",6],["preload",6],["resourceconfig",6],["array",6],["layout",6],["cmdk",6],["пустой",6],["attachments",6],["radiogroup",5],["тот",5],["один",5],["api",5],["interface",5],["default",5],["checked",5],["если",5],["common",5],["items",5],["control",5],["anti",5],["список",5],["все",5],["варианты",5],["компонент",5],["page",5],["totalcount",5],["pagesize",5],["значения",5],["путь",5],["сигнал",5],["validation",5],["maxitems",5],["minlength",5],["там",5],["мульти",5],["src",5],["выбора",4],["контракт",4],["нужен",4],["flex",4],["уже",4],["children",4],["строку",4],["два",4],["всё",4],["выборе",4],["умолчанию",4],["всегда",4],["обычно",4],["источника",4],["static",4],["search",4],["option",4],["можно",4],["res",4],["await",4],["banks",4],["name",4],["json",4],["return",4],["правило",4],["tree",4],["файлы",4],["definevalidationschema",4],["validate",4],["поэтому",4],["dirty",4],["дерева",4],["and",4],["buttons",4],["файл",4],["comboboxtreefield",4],["comboboxtreemultifield",4],["node",4],["уровень",4],["troubleshooting",4],["fields",3],["разных",3],["data",3],["prop",3],["описание",3],["undefined",3],["подпись",3],["справа",3],["рендерится",3],["чекбокс",3],["блокирует",3],["gap",3],["есть",3],["ипотека",3],["составе",3],["передавать",3],["варианта",3],["input",3],["примитив",3],["true",3],["radiooption",3],["вариантов",3],["одним",3],["loan_types",3],["consumer",3],["через",3],["size",3],["который",3],["вне",3],["ничего",3],["срабатывает",3],["inline",3],["сразу",3],["пагинация",3],["стратегия",3],["загрузки",3],["страницы",3],["строке",3],["selectgroup",3],["источник",3],["приходит",3],["подсказка",3],["триггере",3],["когда",3],["над",3],["async",3],["length",3],["rows",3],["total",3],["россия",3],["записи",3]]},{"id":"layout-and-buttons","file":"04-layout-and-buttons.md","title":"Layout and buttons","purpose":"Компоненты, не привязанные к `FieldNode`: `Button`, `AsyncBoundary`, `Tree`, `ExampleCard`, утилита `cn`. Используются как для основных действий формы (submit, prev/next в wizard), для показа данных рядом с ней и для playground-демонстраций.","keyConcepts":["**Два источника узлов.** `nodes` — дерево объявлено целиком; `loadChildren(node)` — уровень","**Прочитанный уровень не забывается.** Свернуть и раскрыть обратно — частое движение, и","**«Уровень не прочитан» ≠ «детей нет».** У ветки `children: undefined` означает первое, поэтому","**Выделение и отмеченный набор — разное.** `selectedId` это «где я сейчас» (одна строка, туда же","**Две идиомы набора, а не россыпь флагов.** `checkOn=\'modifier\'` (умолчание) — навигатор файлов:","**`selectable`** — `\'all\'` (умолчание) или `\'leaf\'`. При `\'leaf\'` щелчок по ветке раскрывает её,","**Виртуальный скролл включён по умолчанию.** Строки фиксированной высоты (24 px), в разметке","**`maxRows` задаёт высоту по содержимому** — то, что нужно списку в поповере: короткое дерево не","**Поиск фильтрует само дерево**, достраивая путь до совпадения: ветки на пути раскрываются на","**`node.id` — адрес, уникальный в пределах всего дерева.** По нему идут раскрытие, выбор, фокус","**Клавиатура принадлежит дереву** и глушится: стрелки (влево — свернуть либо уйти к родителю,"],"api":"```typescript\\ninterface ButtonProps extends React.ComponentProps<\'button\'> {\\n variant?: \'default\' | \'destructive\' | \'outline\' | \'secondary\' | \'ghost\' | \'link\';\\n size?: \'default\' | \'sm\' | \'lg\' | \'icon\' | \'icon-sm\' | \'icon-lg\';\\n asChild?: boolean;\\n}\\n```\\n\\n| Variant | Use case |\\n| ------------- | ------------------------------------------------------------------- |\\n| `default` | Основное действие (`Submit`, `Save`). Заполненный фон `bg-primary`. |\\n| `destructive` | Опасное действие (`Delete`, `Remove`). |\\n| `outline` | Вторичное действие (`Cancel`, `Edit`). Прозрачный фон + бордер. |\\n| `secondary` | Между `default` и `outline`. Серый фон. |\\n| `ghost` | Меню, иконки в toolbar. Без фона до hover. |\\n| `link` | Текстовая ссылка с подчёркиванием на hover. |\\n\\n| Size | Высота | Использование |\\n| --------- | --------- | -------------------------------------- |\\n| `default` | `h-9` | Дефолтный размер для большинства форм. |\\n| `sm` | `h-8` | Компактные toolbar-ы, фильтры. |\\n| `lg` | `h-10` | Финальный CTA, оплата. |\\n| `icon` | `size-9` | Только иконка, default-размер. |\\n| `icon-sm` | `size-8` | Иконка в toolbar. |\\n| `icon-lg` | `size-10` | Иконка hero. |\\n\\n| Prop | Тип | Default | Описание |\\n| --------- | --------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- |\\n| `variant` | union | `\'default\'` | Внешний вид (см. таблицу). |\\n| `size` | union | `\'default\'` | Размер (см. таблицу). |\\n| `asChild` | `boolean` | `false` | Заменить корневой `<button>` на дочерний элемент через `@radix-ui/react-slot`. Требует ровно одного React-элемента в `children`. |\\n\\nВсе остальные пропсы (`onClick`, `disabled`, `type`, `aria-*`, `data-*`)\\nпрокидываются как у нативного `<button>`.","patterns":[{"lang":"tsx","code":"import { Button } from \'@reformer/ui-kit\';\\n\\n<Button type=\\"submit\\" disabled={isSubmitting}>\\n {isSubmitting ? \'Отправка...\' : \'Отправить\'}\\n</Button>;"},{"lang":"tsx","code":"{\\n ([\'default\', \'destructive\', \'outline\', \'secondary\', \'ghost\', \'link\'] as const).map((variant) => (\\n <Button key={variant} variant={variant}>\\n {variant}\\n </Button>\\n ));\\n}"},{"lang":"tsx","code":"import { Link } from \'react-router-dom\';\\nimport { Button } from \'@reformer/ui-kit\';\\n\\n<Button asChild variant=\\"outline\\">\\n <Link to=\\"/dashboard\\">Открыть дашборд</Link>\\n</Button>;"},{"lang":"tsx","code":"<Button asChild>\\n <a href=\\"/report.pdf\\" download>\\n Скачать отчёт\\n </a>\\n</Button>"},{"lang":"tsx","code":"import { PlusIcon } from \'lucide-react\';\\n\\n<Button size=\\"sm\\">\\n <PlusIcon /> Добавить\\n</Button>;"},{"lang":"tsx","code":"<Button size=\\"icon\\" variant=\\"ghost\\" aria-label=\\"Закрыть\\">\\n <XIcon />\\n</Button>"},{"lang":"tsx","code":"import { AsyncBoundary } from \'@reformer/ui-kit\';\\n\\nfunction ApplicationPage({ applicationId, form }: Props) {\\n return (\\n <AsyncBoundary\\n load={(signal) => loadApplication(applicationId, signal)}\\n loadKey={applicationId}\\n enabled={applicationId !== null}\\n onSuccess={(data) => form.patchValue(data)}\\n delayMs={200}\\n >\\n <CreditForm form={form} />\\n </AsyncBoundary>\\n );\\n}"},{"lang":"tsx","code":"import { useRef } from \'react\';\\nimport type { AsyncBoundaryHandle } from \'@reformer/cdk/async-boundary\';\\n\\nconst boundaryRef = useRef<AsyncBoundaryHandle<Application>>(null);\\n\\n<button onClick={() => boundaryRef.current?.reload()}>Обновить</button>\\n<AsyncBoundary ref={boundaryRef} load={loadApplication}>…</AsyncBoundary>;"},{"lang":"tsx","code":"<AsyncBoundary status={status} error={error} onRetry={reload}>\\n <CountriesList countries={countries} />\\n</AsyncBoundary>"},{"lang":"tsx","code":"<AsyncBoundary\\n status={status}\\n loadingSlot={\\n <div className=\\"space-y-2\\">\\n {[0, 1, 2].map((i) => (\\n <Skeleton key={i} className=\\"h-9 w-full\\" />\\n ))}\\n </div>\\n }\\n>\\n <DataTable rows={rows} />\\n</AsyncBoundary>"},{"lang":"tsx","code":"import { Tree } from \'@reformer/ui-kit\';\\n\\n<Tree\\n loadChildren={(node) => fs.list(node?.id ?? \'/\')}\\n selectedId={path}\\n onSelectedChange={setPath}\\n selectable=\\"leaf\\"\\n onActivate={(node, { preview }) => (preview ? openPreview(node.id) : openPinned(node.id))}\\n className=\\"h-full\\"\\n data-testid=\\"files\\"\\n/>;"},{"lang":"tsx","code":"import { useRef } from \'react\';\\nimport { Tree, type TreeHandle } from \'@reformer/ui-kit\';\\n\\nconst treeRef = useRef<TreeHandle>(null);\\n\\n<Tree\\n ref={treeRef}\\n nodes={project}\\n selectionMode=\\"multiple\\" // Ctrl/Cmd — по одной, Shift — диапазон, Escape — снять набор\\n onContextMenu={openMenu}\\n renderActions={(node) => (node.failed ? <AlertIcon /> : null)}\\n/>;\\n\\n// Что удалять: набор, если выделение внутри него, иначе одна выделенная строка.\\nconst targets = treeRef.current?.getActionTargets() ?? [];"},{"lang":"tsx","code":"const [query, setQuery] = useState(\'\');\\n\\n<div className=\\"space-y-2\\">\\n <Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder=\\"Поиск по файлам\\" />\\n <Tree nodes={project} search={query} maxRows={12} emptyText=\\"Ничего не найдено\\" />\\n</div>;"},{"lang":"tsx","code":"import { ExampleCard, InputField } from \'@reformer/ui-kit\';\\n\\n<ExampleCard\\n title=\\"Input — базовый\\"\\n description=\\"Однострочное поле с placeholder\\"\\n code={`<Input value={v} onChange={setV} placeholder=\\"Email\\" />`}\\n>\\n <Input value={v} onChange={setV} placeholder=\\"Email\\" />\\n</ExampleCard>;"},{"lang":"typescript","code":"import { cn } from \'@reformer/ui-kit\';\\n\\ncn(\'px-2 py-1\', isActive && \'bg-blue-500\', \'px-4\');\\n// → \'py-1 bg-blue-500 px-4\' (px-2 затёрт px-4)"},{"lang":"tsx","code":"import { cn } from \'@reformer/ui-kit\';\\n\\nconst Card = React.forwardRef<HTMLDivElement, { className?: string }>(\\n ({ className, ...props }, ref) => (\\n <div ref={ref} className={cn(\'rounded-lg border p-4\', className)} {...props} />\\n )\\n);"}],"antiPatterns":[{"note":"- `asChild` с несколькими элементами в `children` — Radix Slot падает; нужен\\n ровно один React-элемент.\\n- `<Button as=\\"a\\">` — у `Button` нет prop\'а `as`, используй `asChild`.\\n- Передавать `className` для смены `variant`-цветов вместо одной из\\n вариант-опций — теряется консистентность темы.\\n- `size=\\"icon\\"` без иконки — будет квадрат `h-9 w-9` без видимого контента."},{"note":"- **Не** схлопывать «нечего грузить» в `ready`: для формы создания (`id === null`)\\n используйте `idle`, иначе пустая форма неотличима от успешно загруженной.\\n- **Не** сообщать пустой результат через `status: \'error\'` — ноль записей это успех.\\n Пустоту рисует `AsyncBoundaryEmpty` внутри `ready`.\\n- **Не** рисовать кнопку повтора без рабочего `onRetry`: неработающий контрол ловит\\n фокус и читается скринридером. Компонент скрывает её сам, когда `onRetry` не задан.\\n- Нужен полный контроль над составом состояний — берите headless-версию из\\n `@reformer/cdk/async-boundary`, а не копируйте стилизованную."},{"note":"- Передавать в `LoadingComponent` готовый `<div>` (ReactNode) вместо\\n компонента — будет ошибка типов; нужно `() => <div>...</div>`.\\n- Использовать `AsyncBoundary` вместо `Suspense` для React-Suspense-данных —\\n это разные механизмы. `AsyncBoundary` — простая state-машина, не\\n перехватывает throw."},{"note":"- Собирать `id` из имени узла — два `index.ts` в разных каталогах схлопнутся в один адрес, и две\\n строки начнут раскрываться и выделяться вместе. Адрес обязан быть уникальным в пределах дерева.\\n- Обновлять содержимое ветки заменой `nodes`, когда уровень уже прочитан лениво: прочитанный\\n уровень перекрывает объявленный, и новые данные до строки не дойдут. Перечитывание —\\n `refresh(id)` у handle.\\n- Держать `selectedId` и «что выбрано» одним списком — выделение отвечает на «где я», набор на\\n «к чему применится действие»; слитые вместе, они ломают Shift-диапазон и клавиатуру.\\n- Оставлять виртуализацию включённой при серверной отрисовке — без метрик вьюпорта в разметку\\n попадает только окно из девяти строк. Для страниц документации `virtualized={false}`.\\n- Ставить дерево в форму как поле (`component: Tree`) — value-seam ему нечем принять: ни `value`,\\n ни `onChange` у него нет. Значение из иерархии даёт `ComboboxTreeField`.\\n- Обвешивать строки собственными классами фона и рамки: вид строки — часть компонента, а темой\\n управляют токены. Своё содержимое добавляют слотами `renderIcon` / `renderLabel` /\\n `renderActions`."},{"note":"- Использовать в продакшене — это playground-utility, не component-library\\n primitive. Кнопка переключения «глаз/код» не настраивается."},{"note":"- Использовать `cn` вместо строки в случае без условий — `cn(\'a b c\')` работает,\\n но избыточен. Достаточно `\'a b c\'`.\\n- Передавать массивы/объекты, рассчитывая на shadcn-стиль `cn({active: true})`:\\n `clsx`-синтаксис поддерживается, но удобнее писать через `&&`."}],"examples":[],"troubleshooting":[],"seeAlso":["[03-choice-fields.md](03-choice-fields.md) — `ComboboxTreeField` / `ComboboxTreeMultiField`: значение из иерархии.","[05-form-field-integration.md](05-form-field-integration.md) — как `Button` используется в `FormWizard.Actions`.","[10-imperative-handles.md](10-imperative-handles.md) — `TreeHandle`: раскрытие уровней, `refresh`, цели действия.","[06-troubleshooting.md](06-troubleshooting.md) — «forwardRef + Slot конфликты», «AsyncBoundary не переключает состояние», ловушки дерева."],"sections":[{"heading":"Button","slug":"button"},{"heading":"AsyncBoundary","slug":"asyncboundary"},{"heading":"Tree","slug":"tree"},{"heading":"ExampleCard","slug":"examplecard"},{"heading":"cn","slug":"cn"},{"heading":"See also","slug":"see-also-4"}],"terms":[["button",24],["react",23],["string",21],["для",19],["reactnode",18],["asyncboundary",15],["tsx",15],["node",15],["default",13],["import",13],["from",13],["reformer",13],["classname",12],["error",12],["tree",11],["variant",11],["boolean",11],["patterns",11],["status",11],["null",11],["набор",11],["уровень",11],["строки",11],["data",10],["kit",10],["aschild",9],["без",9],["size",9],["children",9],["icon",8],["void",8],["при",8],["div",8],["дерево",8],["дерева",8],["link",7],["через",7],["aria",7],["idle",7],["form",7],["value",7],["outline",6],["только",6],["описание",6],["const",6],["anti",6],["вместо",6],["загрузки",6],["ошибки",6],["load",6],["onretry",6],["него",6],["ref",6],["щелчок",6],["examplecard",5],["как",5],["typescript",5],["действие",5],["иконка",5],["prop",5],["false",5],["type",5],["common",5],["нет",5],["ready",5],["нужно",5],["блок",5],["self",5],["managed",5],["состояние",5],["signal",5],["иначе",5],["функция",5],["applicationid",5],["когда",5],["это",5],["onchange",5],["nodes",5],["ветки",5],["строка",5],["что",5],["строк",5],["leaf",5],["treenode",5],["формы",4],["submit",4],["данных",4],["кнопка",4],["slot",4],["api",4],["interface",4],["destructive",4],["secondary",4],["ghost",4],["тип",4],["disabled",4],["label",4],["компонент",4],["сам",4],["controlled",4],["unknown",4],["number",4],["внутри",4],["useref",4],["читается",4],["поле",4],["выделение",4],["отмеченный",4],["choice",4],["fields",4],["refresh",4],["selectedid",4],["файлов",4],["escape",4],["поиск",4],["адрес",4],["readonly",4],["title",4],["preview",4],["treehandle",4],["imperative",4],["handles",4],["input",4],["placeholder",4],["playground",3],["radix",3],["режим",3],["или",3],["фон",3],["toolbar",3],["фона",3],["размер",3],["документации",3],["key",3],["один",3],["передавать",3],["loading",3],["над",3],["cdk",3],["async",3],["boundary",3],["два",3],["refreshing",3],["asyncstatus",3],["promise",3],["loadkey",3],["enabled",3],["onsuccess",3],["delayms",3],["loadingslot",3],["errorslot",3],["запрос",3],["создания",3],["например",3],["текст",3],["умолчанию",3],["props",3],["компонента",3],["boundaryref",3],["full",3],["фокус",3],["полный",3],["использовать",3],["проекта",3],["раскрытие",3],["иерархии",3],["значение",3],["поверх",3],["comboboxtreefield",3],["целиком",3],["loadchildren",3],["вместе",3],["раскрыть",3],["можно",3],["handle",3],["каталог",3],["где",3],["checkon",3],["modifier",3],["умолчание",3],["shift",3],["диапазон",3],["click",3],["пробел",3],["selectionmode",3],["multiple",3],["selectable",3],["all",3],["virtualized",3],["maxrows",3],["путь",3],["содержимое",3],["пределах",3],["testid",3],["уровня",3],["управляемо",3],["старте",3],["true",3],["renderactions",3],["treeref",3]]},{"id":"form-field-integration","file":"05-form-field-integration.md","title":"FormField integration","purpose":"`FormField` из `@reformer/ui-kit` — это готовая обёртка-«склейка» поверх headless-компонента `FormField` из [`@reformer/cdk`](../../../reformer-cdk/). Она автоматически рендерит `Label` → `Control` → `Error`, читает `pending`-флаг для async-валидаций и подставляет `data-testid` для e2e.","keyConcepts":[],"api":"```typescript\\ninterface FormFieldProps {\\n control: FieldNode<any>;\\n className?: string;\\n testId?: string;\\n /** Кастомный input — для использования с RenderSchema fieldWrapper */\\n children?: React.ReactNode;\\n}\\n```\\n\\n| Prop | Тип | Описание |\\n| ----------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |\\n| `control` | `FieldNode<T>` | Поле формы. Из него берутся `component`, `componentProps`, `value`, `error`, `pending`, `setValue`, `blur`. |\\n| `className` | `string` | Класс корневой `<div>`-обёртки. |\\n| `testId` | `string` | Префикс для `data-testid` (`field-<id>`, `label-<id>`, `input-<id>`, `error-<id>`). Если опущен — пытается взять `componentProps.testId`. Иначе `\'unknown\'`. |\\n| `children` | `ReactNode` | Кастомный контрол: оборачивается в `CdkFormField.Control asChild`. См. сценарий 3. |\\n\\n`FormField` обёрнут в `React.memo` со сравнением по ссылочному равенству\\n`control` — это критично для производительности больших форм (при ререндере\\nродителя поле не пересчитывается, пока не сменился сам `FieldNode`).","patterns":[],"antiPatterns":[{"note":"- Передавать `control` другого типа (`FormProxy`, `ArrayNode`) — ожидается\\n именно `FieldNode<T>`. Для массивов используй `FormArray.Root` из CDK; для\\n groups — отдельные `FormField` на каждое лиственное поле.\\n- Динамически менять `control` (`<FormField control={isAdvanced ? form.x : form.y} />`)\\n — `React.memo` не пересоздаст внутренний `Root`, но сам `Root` сменит контекст,\\n что может привести к лишнему re-mount контрола. Предпочтительно условно\\n рендерить два разных `FormField`.\\n- Перекрывать `componentProps.testId` через атрибут — побеждает явный\\n `testId`-prop `FormField`, поэтому смесь даёт неожиданный результат. Выбирай\\n один источник.\\n- Использовать `FormField` для чисто декоративных компонентов (заголовков,\\n баннеров) — обёртка ставит `Label` и слот ошибки, что нелогично. Для такого\\n рендерь компоненты напрямую (через container-узлы `Box`/`Section`)."}],"examples":[],"troubleshooting":[],"seeAlso":["[02-text-fields.md](02-text-fields.md), [03-choice-fields.md](03-choice-fields.md) — компоненты, которые `FormField` оборачивает.","[04-layout-and-buttons.md](04-layout-and-buttons.md) — `Button` для submit/prev/next.","[06-troubleshooting.md](06-troubleshooting.md) — «label дублируется», «error не появляется», «FormField не подцепляет ошибки».","CDK-хуки: [@reformer/cdk/form-field](../../../reformer-cdk/docs/llms/) (`FormField.Root`, `useFormFieldContext`)."],"sections":[{"heading":"API","slug":"api"},{"heading":"Common Patterns","slug":"common-patterns"},{"heading":"Anti-patterns","slug":"anti-patterns"},{"heading":"See also","slug":"see-also-5"}],"terms":[["testid",31],["formfield",30],["label",26],["control",23],["reformer",19],["value",18],["для",17],["form",15],["componentprops",14],["kit",13],["component",13],["model",13],["import",12],["from",12],["error",11],["email",11],["react",10],["const",10],["schema",10],["cdkformfield",9],["input",9],["root",8],["cdk",7],["data",7],["tsx",7],["сам",7],["checkbox",7],["fieldwrapper",7],["children",7],["inputfield",7],["classname",6],["field",6],["onchange",6],["fieldnode",6],["string",6],["createform",6],["country",6],["через",6],["accept",6],["контрол",5],["bank",5],["onblur",4],["кастомный",4],["если",4],["usememo",4],["createmodel",4],["button",4],["return",4],["renderer",4],["phone",4],["existingloan",4],["inline",4],["checkboxfield",4],["fields",4],["автоматически",3],["pending",3],["под",3],["div",3],["использования",3],["поле",3],["оборачивается",3],["core",3],["registrationform",3],["formrenderer",3],["что",3],["section",3],["settings",3],["рядом",3],["компоненты",3],["docs",3],["условия",3],["поэтому",3],["это",2],["обёртка",2],["headless",2],["рендерит",2],["вручную",2],["span",2],["проверка",2],["select",2],["без",2],["renderschema",2],["reactnode",2],["prop",2],["blur",2],["обёртки",2],["иначе",2],["aschild",2],["сценарий",2],["memo",2],["patterns",2],["каждого",2],["поля",2],["selectfield",2],["type",2],["function",2],["space",2],["submit",2],["появляется",2],["или",2],["каждый",2],["контракт",2],["рендерер",2],["createrenderschema",2],["createcreditapplicationmodel",2],["источник",2],["creditapplication",2],["amount",2],["только",2],["обвязку",2],["based",2],["seam",2],["контролы",2],["resolvefieldadapter",2],["контрола",2],["нужен",2],["llms",2],["случаев",2],["aria",2],["invalid",2],["mask",2],["используй",2],["напрямую",2],["обёртку",2],["контролов",2],["reformerlayout",2],["маркер",2],["boolean",2],["использовать",2],["ошибки",2],["text",2],["choice",2],["layout",2],["and",2],["buttons",2],["troubleshooting",2]]},{"id":"troubleshooting","file":"06-troubleshooting.md","title":"Troubleshooting / FAQ","purpose":"Частые ошибки при использовании `@reformer/ui-kit` и пути их решения.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md) — список компонентов и их назначения.","[02-text-fields.md](02-text-fields.md), [03-choice-fields.md](03-choice-fields.md), [04-layout-and-buttons.md](04-layout-and-buttons.md) — детали по каждому компоненту; `Tree` в 04, его варианты комбобокса в 03.","[05-form-field-integration.md](05-form-field-integration.md) — `FormField` standalone и как `fieldWrapper`."],"sections":[{"heading":"1. `Input type=\\"number\\"` возвращает строку, а не число (или `null`)","slug":"input-type-number-vozvraschaet-stroku-a-ne-chislo-ili-null"},{"heading":"2. `Select` не показывает options (пустой дропдаун)","slug":"select-ne-pokazyvaet-options-pustoy-dropdaun"},{"heading":"3. `InputMask` пропускает символы или не вставляет литералы","slug":"inputmask-propuskaet-simvoly-ili-ne-vstavlyaet-literaly"},{"heading":"4. `forwardRef` + Radix `Slot` конфликты","slug":"forwardref-radix-slot-konflikty"},{"heading":"5. `Checkbox` value не сохраняется (всегда `false`)","slug":"checkbox-value-ne-sohranyaetsya-vsegda-false"},{"heading":"6. `FormField` не подцепляет ошибки (`<error>` не появляется)","slug":"formfield-ne-podtseplyaet-oshibki-error-ne-poyavlyaetsya"},{"heading":"7. `onBlur` не срабатывает на `Select` / `RadioGroup`","slug":"onblur-ne-srabatyvaet-na-select-radiogroup"},{"heading":"8. `cn` стирает мои классы или, наоборот, оставляет лишние","slug":"cn-stiraet-moi-klassy-ili-naoborot-ostavlyaet-lishnie"},{"heading":"9. `AsyncBoundary` не переключает состояние","slug":"asyncboundary-ne-pereklyuchaet-sostoyanie"},{"heading":"10. `InputPassword`: иконка-«глаз» не появляется","slug":"inputpassword-ikonka-glaz-ne-poyavlyaetsya"},{"heading":"11. JSON-renderer: `Select`-`options` хранятся в реестре, но в дропдауне пусто","slug":"json-renderer-select-options-hranyatsya-v-reestre-no-v-dropdaune-pusto"},{"heading":"12. Мультивыбор не рендерится, а submit молча не проходит","slug":"multivybor-ne-renderitsya-a-submit-molcha-ne-prohodit"},{"heading":"13. Поиск в дереве не находит файл, который точно есть","slug":"poisk-v-dereve-ne-nahodit-fayl-kotoryy-tochno-est"},{"heading":"14. Две строки дерева ведут себя как одна","slug":"dve-stroki-dereva-vedut-sebya-kak-odna"},{"heading":"15. При серверной отрисовке в разметку дерева попадает девять строк","slug":"pri-servernoy-otrisovke-v-razmetku-dereva-popadaet-devyat-strok"},{"heading":"See also","slug":"see-also-6"}],"terms":[["value",20],["error",16],["симптом",15],["form",15],["без",14],["tsx",13],["если",13],["button",13],["при",12],["options",12],["formfield",12],["model",12],["asyncboundary",12],["или",11],["для",11],["решение",11],["null",10],["const",10],["причина",9],["select",9],["false",9],["classname",9],["reformer",8],["input",8],["number",8],["react",8],["нет",8],["поле",7],["onchange",7],["причины",7],["children",7],["ref",7],["только",7],["после",7],["это",7],["ошибки",6],["через",6],["внутри",6],["один",6],["undefined",6],["как",6],["submit",6],["status",6],["дерева",6],["kit",5],["schema",5],["приходит",5],["всего",5],["всегда",5],["typescript",5],["передан",5],["сразу",5],["loading",5],["либо",5],["компонент",5],["field",5],["slot",5],["что",5],["href",5],["boolean",5],["accept",5],["появляется",5],["touched",5],["index",5],["строку",4],["resource",4],["тот",4],["всё",4],["true",4],["пользователь",4],["значение",4],["integration",4],["forwardref",4],["aschild",4],["link",4],["проверь",4],["createmodel",4],["есть",4],["поэтому",4],["validatemodel",4],["import",4],["from",4],["onblur",4],["срабатывает",4],["делает",4],["нужен",4],["json",4],["datasource",4],["loan_types",4],["label",4],["tags",4],["tree",4],["fields",4],["type",3],["age",3],["пустой",3],["обязательно",3],["строка",3],["string",3],["radix",3],["используй",3],["mask",3],["форме",3],["ничего",3],["ошибку",3],["mylink",3],["checked",3],["createform",3],["headless",3],["cdk",3],["blur",3],["markastouched",3],["кнопка",3],["validation",3],["значения",3],["city",3],["div",3],["ещё",3],["onretry",3],["который",3],["content",3],["showtoggle",3],["renderer",3],["comboboxtreemulti",3],["поиск",3],["loadchildren",3],["строки",3],["found",3],["nodes",3],["ключ",3],["src",3],["layout",3],["решения",2],["возвращает",2],["число",2],["пустого",2],["скорее",2],["контракт",2],["setage",2],["использовать",2],["ввод",2],["load",2],["источник",2],["inputmask",2],["пропускает",2],["вставляет",2],["литералы",2],["появляются",2],["автоматически",2],["placeholder",2],["рендерятся",2],["transformvalue",2],["raw",2],["imask",2],["рядом",2],["span",2],["ровно",2],["элемент",2],["произойдёт",2],["вычисляется",2],["текста",2],["props",2],["checkbox",2],["пуст",2],["нужно",2],["модели",2],["начальное",2],["setvalue",2],["ошибка",2],["рендерится",2],["используется",2],["проблема",2],["умолчанию",2],["помечаем",2],["схеме",2],["validationschema",2],["core",2],["validate",2],["async",2],["radiogroup",2],["подсветки",2],["выбор",2],["читает",2],["componentprops",2],["fieldnode",2],["руками",2],["оставляет",2],["дефолт",2],["компоненте",2],["дефолтов",2],["работает",2],["idle",2],["reload",2],["полный",2],["разметка",2],["root",2],["inputpassword",2],["иконка",2],["hasvalue",2],["реестре",2]]},{"id":"form-wizard","file":"07-form-wizard.md","title":"FormWizard — multi-step форма","purpose":"`@reformer/ui-kit/form-wizard` — стилизованный wrapper поверх headless `@reformer/cdk/form-wizard`. Один компонент покрывает все три флоу: TS-схема, renderer-react RenderSchema, renderer-json.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Базовое использование","slug":"bazovoe-ispolzovanie"},{"heading":"Полиморфный `step.body`","slug":"polimorfnyy-step-body"},{"heading":"RenderNode body (renderer-react / renderer-json)","slug":"rendernode-body-renderer-react-renderer-json"},{"heading":"JSON","slug":"json"},{"heading":"Compound API","slug":"compound-api"},{"heading":"Ref / handle","slug":"ref-handle"}],"terms":[["formwizard",21],["reformer",21],["model",21],["const",20],["form",19],["body",17],["renderer",16],["myform",16],["values",14],["react",13],["submit",13],["import",12],["from",12],["component",12],["email",11],["control",11],["wizard",10],["step",9],["kit",9],["tsx",9],["type",9],["rendernode",9],["boolean",8],["steps",8],["config",8],["promise",8],["current",8],["json",7],["validatemodel",7],["password",7],["layout",7],["null",7],["без",7],["rendercontextprovider",7],["wizardref",7],["formfield",6],["inputfield",6],["formwizardhandle",6],["definevalidationschema",6],["validate",6],["внутри",6],["только",6],["value",6],["componentprops",6],["number",6],["cdk",5],["formproxy",5],["core",5],["validationschema",5],["для",5],["confirmation",5],["schema",5],["title",5],["icon",5],["validateall",5],["формы",5],["navref",5],["onsubmit",5],["await",5],["api",5],["renderstepbody",5],["его",5],["formrenderer",5],["схема",4],["formwizardconfig",4],["required",4],["string",4],["валидация",4],["отдельный",4],["шаг",4],["поля",4],["через",4],["это",4],["если",4],["канон",4],["ref",4],["handlesubmit",4],["flow",4],["отдаёт",4],["rendernodecomponent",4],["render",4],["шим",4],["indicator",4],["один",3],["три",3],["renderschema",3],["useref",3],["apply",3],["validation",3],["схемы",3],["валидаторов",3],["модели",3],["label",3],["void",3],["step_schemas",3],["validatestep",3],["колбэк",3],["возвращает",3],["сам",3],["оба",3],["callback",3],["принимает",3],["result",3],["вызывается",3],["когда",3],["reactnode",3],["нужен",3],["box",3],["node",3],["модуля",3],["directory",3],["форма",2],["поверх",2],["headless",2],["компонент",2],["все",2],["formwizardstep",2],["checkboxfield",2],["createmodel",2],["createform",2],["formmodel",2],["minlength",2],["constraint",2],["extends",2],["record",2],["any",2],["generic",2],["листья",2],["ссылаются",2],["сигналы",2],["false",2],["testid",2],["пароль",2],["правила",2],["step1validation",2],["step2validation",2],["step3validation",2],["fullvalidation",2],["step1",2],["step2",2],["прогонять",2],["нодам",2],["makevalidationconfig",2],["шага",2],["имеет",2],["аргумента",2],["async",2],["колбэка",2],["получает",2],["прошла",2],["runtime",2],["componenttype",2],["tbody",2],["про",2],["рендерер",2],["знает",2],["стратегии",2],["path",2],["createrenderschema",2],["creditapplication",2],["стратегия",2],["wizardform",2],["кредит",2],["children",2],["loanamount",2],["loanterm",2],["приложение",2],["которым",2],["рендерит",2],["как",2],["root",2],["settings",2],["fieldwrapper",2],["напрямую",2],["приложения",2],["rendererformwizard",2],["файл",2],["mcp",2],["props",2],["gotostep",2],["gotonextstep",2],["gotopreviousstep",2],["validatecurrentstep",2]]},{"id":"form-array-section","file":"08-form-array-section.md","title":"FormArraySection — UI для FormArray","purpose":"`@reformer/ui-kit/form-array` — стилизованный wrapper поверх headless `@reformer/cdk/form-array`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Базовое использование (TS-flow)","slug":"bazovoe-ispolzovanie-ts-flow"},{"heading":"Renderer-react RenderSchema","slug":"renderer-react-renderschema"},{"heading":"JSON (renderer-json)","slug":"json-renderer-json"},{"heading":"Props (полный список)","slug":"props-polnyy-spisok"},{"heading":"Critical: `initialValue` — PLAIN LEAVES ONLY","slug":"critical-initialvalue-plain-leaves-only"}],"terms":[["control",21],["component",19],["type",16],["formarraysection",13],["array",13],["json",13],["initialvalue",12],["model",12],["formarray",11],["form",10],["string",10],["properties",10],["renderer",9],["itemcomponent",9],["имущество",9],["item",9],["для",8],["reformer",7],["добавить",7],["description",6],["estimatedvalue",6],["componentprops",6],["value",6],["kit",5],["import",5],["from",5],["formproxy",5],["property",5],["apartment",5],["propertyform",5],["renderschema",4],["items",4],["тип",4],["элемента",4],["number",4],["section",4],["title",4],["addbuttonlabel",4],["emptymessage",4],["plain",4],["без",4],["template",4],["false",4],["flow",3],["react",3],["tsx",3],["classname",3],["space",3],["formfield",3],["partial",3],["fieldconfig",3],["createrenderschema",3],["массив",3],["arraynode",3],["секция",3],["кнопки",3],["при",3],["boolean",3],["wrapper",2],["массива",2],["чего",2],["контракт",2],["onadd",2],["onremove",2],["onmove",2],["инъектит",2],["про",2],["interface",2],["formfields",2],["требует",2],["index",2],["который",2],["const",2],["generic",2],["formarrayproxy",2],["нажмите",2],["добавления",2],["hasitems",2],["modelarray",2],["внутри",2],["selector",2],["selfmanagedchildren",2],["true",2],["children",2],["field",2],["нужен",2],["это",2],["конвертер",2],["reg",2],["нода",2],["jsonc",2],["itemlabel",2],["options",2],["datasource",2],["property_types",2],["textarea",2],["рендерит",2],["под",2],["пропа",2],["required",2],["componenttype",2],["каждого",2],["текст",2],["удалить",2],["показывать",2],["класс",2],["обёртки",2],["авто",2],["инъекция",2],["object",2]]},{"id":"input-mask","file":"09-input-mask.md","title":"InputMask — поля с маской ввода","purpose":"`InputMask` из `@reformer/ui-kit` — input с placeholder-маской: символ `\'9\'` означает «цифра», остальные символы (`+`, `-`, `(`, `)`, пробел, точка) — литералы для подсказки формата в placeholder.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-text-fields.md](02-text-fields.md) — обычный Input","[05-form-field-integration.md](05-form-field-integration.md) — FormField обёртка","[06-troubleshooting.md](06-troubleshooting.md) — «маска не вставляется автоматически» → используй `react-input-mask`"],"sections":[{"heading":"Schema-driven (canonical pattern)","slug":"schema-driven-canonical-pattern"},{"heading":"Common masks","slug":"common-masks"},{"heading":"Validation","slug":"validation"},{"heading":"Advanced — strict mask через FormField + children slot","slug":"advanced-strict-mask-cherez-formfield-children-slot"},{"heading":"See also","slug":"see-also-7"}],"terms":[["model",18],["formfield",15],["mask",14],["form",11],["reformer",10],["phone",9],["testid",9],["input",8],["import",8],["from",8],["pattern",7],["component",7],["componentprops",7],["passport",7],["inn",7],["snils",7],["inputmask",6],["schema",6],["value",6],["field",6],["core",6],["validate",6],["validation",6],["required",6],["const",6],["control",6],["inputmaskfield",5],["телефон",5],["message",5],["kit",4],["как",4],["react",4],["definevalidationschema",4],["contactform",4],["string",4],["label",4],["паспорта",4],["инн",4],["integration",4],["placeholder",3],["для",3],["маска",3],["формат",3],["используй",3],["через",3],["createmodel",3],["layout",3],["createform",3],["правила",3],["validators",3],["серия",3],["номер",3],["contactvalidation",3],["literal",3],["validatemodel",3],["поля",2],["маской",2],["автоматическая",2],["вставка",2],["это",2],["маски",2],["или",2],["imask",2],["driven",2],["схема",2],["отдельной",2],["children",2],["снилс",2],["tsx",2],["символами",2],["схему",2],["выше",2],["символов",2],["await",2],["get",2],["cross",2],["child",2],["text",2],["fields",2],["troubleshooting",2]]},{"id":"imperative-handles","file":"10-imperative-handles.md","title":"Императивные handle полей — управление компонентом по селектору","purpose":"Каждое поле ui-kit экспонирует типизированный императивный handle через `ref`. Из render-схемы он достаётся по селектору: `schema.node(sel).getRef<H>()`. Это мост «узел схемы → живой компонент», тот же, что уже использовался для `FormWizard`/`FormArray`, но теперь работает и для листовых полей.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Когда императив, а когда реактив","slug":"kogda-imperativ-a-kogda-reaktiv"},{"heading":"Базовое использование","slug":"bazovoe-ispolzovanie-2"},{"heading":"⚠️ `getRef()` вызывать ДО первого рендера","slug":"getref-vyzyvat-do-pervogo-rendera"},{"heading":"Адресация: `selector` или `__path`","slug":"adresatsiya-selector-ili-path"},{"heading":"Контракты handle","slug":"kontrakty-handle"},{"heading":"Рецепт: focus первого невалидного поля после submit","slug":"retsept-focus-pervogo-nevalidnogo-polya-posle-submit"},{"heading":"Рецепт: зависимый async-Select","slug":"retsept-zavisimyy-async-select"},{"heading":"Рецепт: фокус в поле только что добавленной строки FormArray","slug":"retsept-fokus-v-pole-tolko-chto-dobavlennoy-stroki-formarray"},{"heading":"null-safety и жизненный цикл","slug":"null-safety-i-zhiznennyy-tsikl"},{"heading":"Своё поле с handle","slug":"svoe-pole-s-handle"}],"terms":[["reformer",21],["getref",19],["ref",17],["current",17],["kit",16],["schema",16],["const",16],["handle",14],["node",14],["fieldhandle",14],["focus",10],["import",10],["from",10],["value",9],["поле",8],["model",8],["email",8],["null",8],["через",7],["для",7],["tsx",7],["path",7],["phones",7],["open",6],["react",6],["type",6],["selector",6],["withformcontrol",6],["полей",5],["императивный",5],["что",5],["реактивный",5],["scrollintoview",5],["component",5],["рендера",5],["emailref",5],["после",5],["все",5],["поля",5],["close",5],["clear",5],["city",5],["formarray",4],["только",4],["selectasynchandle",4],["reload",4],["rendereffect",4],["inputfield",4],["number",4],["validatemodel",4],["рецепт",4],["combobox",4],["refresh",4],["схемы",3],["тот",3],["уже",3],["работает",3],["реактивно",3],["иначе",3],["field",3],["patchprops",3],["blur",3],["async",3],["true",3],["renderer",3],["первого",3],["behavior",3],["сигнал",3],["ноды",3],["поэтому",3],["submit",3],["ключ",3],["модели",3],["без",3],["signalat",3],["ошибки",3],["пути",3],["схеме",3],["baseline",3],["getnodeforsignal",3],["return",3],["firstinvalid",3],["sig",3],["country",3],["fields",3],["fieldadapter",3],["export",3],["селектору",2],["sel",2],["это",2],["узел",2],["компонент",2],["formwizard",2],["когда",2],["остаётся",2],["его",2],["делать",2],["слой",2],["видимость",2],["поповер",2],["loadmore",2],["источника",2],["inputpasswordhandle",2],["setvisible",2],["createrenderschema",2],["myform",2],["ниже",2],["обработчика",2],["smooth",2],["block",2],["center",2],["нода",2],["останется",2],["onclick",2],["первый",2],["внутри",2],["селектора",2],["один",2],["где",2],["или",2],["сигнала",2],["адресуется",2],["pwd",2],["password",2],["inputpasswordfield",2],["путь",2],["тому",2],["нужно",2],["rich",2],["tree",2],["treehandle",2],["barrel",2],["доступны",2],["своим",2],["уровень",2],["пока",2],["открытие",2],["тип",2],["как",2],["резолвится",2],["core",2],["order",2],["порядок",2],["length",2],["formarrayhandle",2],["ещё",2],["queuemicrotask",2],["idx",2],["сам",2],["опциональны",2],["примитива",2],["при",2],["компонента",2],["myadapter",2],["useimperativehandle",2],["exposeshandle",2]]},{"id":"form-layout","file":"11-form-layout.md","title":"Form layout — отступы, сетка и группировка полей","purpose":"Правила раскладки формы: чем задавать вертикальный ритм, как собирать поля в строки и группы, где граница между «расположением» и «внешним видом». Короткое правило — **руками пишем только раскладку и отступы, вид берём компонентом кита**. Для полей это кодифицировано в `class-catalog.ts` (`FIELD_CLASS_GROUPS`); документ распространяет то же правило на всю форму.","keyConcepts":["**Разрешённые группы классов** — `layout`, `flex`, `grid`, `spacing`, `responsive`,","**Запрещено руками** — `bg-*`, `text-<цвет>-<оттенок>`, `border-<цвет>`, `shadow-*`,","**Исключение для заголовков** — ровно две комбинации, без цвета: `text-xl font-bold`","**Полю — только `spacing`.** `FormField` и контролы принимают `gap-*` / `m*-*` / `p*-*`;","**Три уровня вертикального ритма** — `space-y-6` (шаг) → `space-y-4` (группа) →","**Внутри поля отступы не пишем** — `Field` уже даёт `gap-3` между подписью и контролом,","**Вид — компонентом**: карточка → `Card`, плашка → `Alert`, разделитель → `Separator`,","**Один макет — три записи.** TSX, `RenderSchema` и JSON используют одни и те же строки"],"api":"","patterns":[{"lang":"tsx","code":"import { Card, CardContent, CardHeader, CardTitle, FormField, Section } from \'@reformer/ui-kit\';\\n\\n<Card>\\n <CardHeader>\\n <CardTitle>Шаг 2. Персональные данные</CardTitle>\\n </CardHeader>\\n <CardContent className=\\"space-y-6\\">\\n <Section title=\\"ФИО\\" titleAs=\\"h3\\" titleClassName=\\"text-lg font-semibold\\" className=\\"space-y-4\\">\\n <div className=\\"grid grid-cols-1 md:grid-cols-3 gap-4\\">\\n <FormField control={form.lastName} testId=\\"lastName\\" />\\n <FormField control={form.firstName} testId=\\"firstName\\" />\\n <FormField control={form.middleName} testId=\\"middleName\\" />\\n </div>\\n </Section>\\n\\n <Section title=\\"Паспорт\\" titleAs=\\"h3\\" titleClassName=\\"text-lg font-semibold\\" className=\\"space-y-4\\">\\n <div className=\\"grid grid-cols-1 md:grid-cols-2 gap-4\\">\\n <FormField control={form.passport.series} testId=\\"series\\" />\\n <FormField control={form.passport.number} testId=\\"number\\" />\\n </div>\\n <FormField control={form.passport.issuedBy} testId=\\"issuedBy\\" />\\n </Section>\\n </CardContent>\\n</Card>;"}],"antiPatterns":[{"why":"Карточка собрана классами — ломает тёмную тему и расходится с китом.","bad":"<section className=\\"space-y-4 bg-white border rounded-xl shadow-sm p-6\\">","correctNote":"Тот же вид даёт компонент.","correct":"<Card><CardContent className=\\"space-y-4\\">{/* … */}</CardContent></Card>"},{"why":"Цвет в заголовке.","bad":"<h2 className=\\"text-xl font-bold text-gray-900\\">Шаг 1</h2>","correctNote":"Только вес; цвет приходит из темы.","correct":"<h2 className=\\"text-xl font-bold\\">Шаг 1</h2>"},{"why":"Сетка навешена на само поле.","bad":"<FormField control={form.city} className=\\"col-span-2\\" />","correctNote":"Ширину задаёт строка-обёртка; full-width поле выносится из сетки.","correct":"<FormField control={form.city} />"},{"why":"Отступы внутри поля — дублируют gap-3 / gap-1.5 из Field.","bad":"<FormField control={form.email} className=\\"mt-2 mb-4\\" />","correctNote":"Ритм задаёт контейнер.","correct":"<div className=\\"space-y-4\\"><FormField control={form.email} /></div>"},{"why":"Жёсткая сетка без брейкпоинта — на телефоне колонки схлопываются.","bad":"<div className=\\"grid grid-cols-2 gap-4\\">","correctNote":"Одна колонка на мобильном, две на десктопе.","correct":"<div className=\\"grid grid-cols-1 md:grid-cols-2 gap-4\\">"},{"why":"max-w-4xl и xl:/2xl: нет в словаре кита — в билдере не соберутся.","bad":"<div className=\\"max-w-4xl mx-auto\\">","correctNote":"Ширина из словаря либо из контейнера приложения.","correct":"<div className=\\"max-w-2xl mx-auto\\">"}],"examples":[],"troubleshooting":[],"seeAlso":["[04-layout-and-buttons.md](04-layout-and-buttons.md) — `Button`, `AsyncBoundary`, `cn`.","[05-form-field-integration.md](05-form-field-integration.md) — что `FormField` рисует сам.","[07-form-wizard.md](07-form-wizard.md) — хром многошаговой формы.","[08-form-array-section.md](08-form-array-section.md) — секция повторяющихся записей.","[renderer-react](../../../reformer-renderer-react/docs/llms/) — layout в `RenderSchema`.","[renderer-json](../../../reformer-renderer-json/docs/llms/) — layout в JSON."],"sections":[{"heading":"Key Concepts","slug":"key-concepts"},{"heading":"Spacing scale","slug":"spacing-scale"},{"heading":"Field grid","slug":"field-grid"},{"heading":"Grouping and sections","slug":"grouping-and-sections"},{"heading":"Layout across targets","slug":"layout-across-targets"},{"heading":"Common Patterns","slug":"common-patterns-2"},{"heading":"Anti-patterns","slug":"anti-patterns-2"},{"heading":"See also","slug":"see-also-8"}],"terms":[["classname",35],["space",24],["grid",23],["form",21],["section",19],["formfield",18],["div",18],["gap",15],["card",15],["tsx",15],["control",14],["text",13],["cols",13],["font",11],["testid",10],["cardcontent",10],["component",10],["поля",8],["layout",7],["отступы",7],["только",7],["semibold",7],["passport",7],["группы",6],["поле",6],["карточка",6],["json",6],["max",6],["titleclassname",6],["полей",5],["классов",5],["шаг",5],["field",5],["даёт",5],["alert",5],["ширину",5],["titleas",5],["cardheader",5],["cardtitle",5],["box",5],["сетка",4],["между",4],["руками",4],["пишем",4],["вид",4],["для",4],["reformer",4],["цвет",4],["bold",4],["задаёт",4],["внутри",4],["секция",4],["заголовком",4],["паспорт",4],["series",4],["number",4],["issuedby",4],["title",4],["componentprops",4],["renderer",4],["формы",3],["ритм",3],["строки",3],["всю",3],["flex",3],["spacing",3],["темы",3],["две",3],["заголовок",3],["контейнер",3],["группа",3],["массива",3],["нет",3],["уже",3],["записи",3],["renderschema",3],["обёртка",3],["сам",3],["сетки",3],["словаре",3],["auto",3],["and",3],["компонент",3],["button",3],["тот",3],["где",2],["правило",2],["компонентом",2],["кита",2],["catalog",2],["словаря",2],["kit",2],["ничего",2],["border",2],["shadow",2],["rounded",2],["фон",2],["рамка",2],["тень",2],["приходят",2],["токенов",2],["ломает",2],["тёмную",2],["тему",2],["без",2],["шага",2],["вокруг",2],["само",2],["три",2],["уровня",2],["элемент",2],["контролом",2],["плашка",2],["меняется",2],["синтаксис",2],["узла",2],["уровень",2],["заголовка",2],["formarray",2],["персональные",2],["данные",2],["фио",2],["col",2],["span",2],["строка",2],["элемента",2],["билдере",2],["issuedate",2],["вес",2],["alerttitle",2],["что",2],["alertdescription",2],["items",2],["center",2],["justify",2],["between",2],["reg",2],["patterns",2],["lastname",2],["firstname",2],["middlename",2],["city",2],["email",2],["buttons",2],["integration",2],["wizard",2],["array",2],["react",2],["docs",2],["llms",2]]}],"symbols":[{"name":"Accordion","kind":"function","signature":"function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/accordion/variants/base/accordion-base.tsx","entries":[".","./accordion"],"package":"@reformer/ui-kit"},{"name":"accordionBasePropsSchema","kind":"const","signature":"export const accordionBasePropsSchema","summary":"Props-схема презентационного `Accordion` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Accordion` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Accordion\'` — каноническое имя в реестре renderer-json.\\nAccordion — обёртка над Radix `Accordion.Root`; сериализуемые пропсы взяты из его API.","params":[],"examplesCount":0,"sourcePath":"src/components/accordion/variants/base/accordion-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AccordionContent","kind":"function","signature":"function AccordionContent({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof AccordionPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/accordion/variants/base/accordion-base.tsx","entries":[".","./accordion"],"package":"@reformer/ui-kit"},{"name":"AccordionItem","kind":"function","signature":"function AccordionItem({\\n className,\\n ...props\\n}: React.ComponentProps<typeof AccordionPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/accordion/variants/base/accordion-base.tsx","entries":[".","./accordion"],"package":"@reformer/ui-kit"},{"name":"AccordionTrigger","kind":"function","signature":"function AccordionTrigger({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof AccordionPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/accordion/variants/base/accordion-base.tsx","entries":[".","./accordion"],"package":"@reformer/ui-kit"},{"name":"actionTargets","kind":"function","signature":"export function actionTargets(rows: readonly TreeRow[]): readonly TreeNode[]","summary":"К чему применится действие: набор, если выделение стоит внутри него, иначе одна строка.","description":"К чему применится действие: набор, если выделение стоит внутри него, иначе одна строка.\\n\\nБез этого правила клавиша и пункт меню отвечали бы на разные вопросы: первая — про строку\\nпод выделением, второй — про набор, и человек не знал бы заранее, что именно произойдёт.\\nПорядок — порядок строк дерева, а не порядок отметок: действие сверху вниз предсказуемо,\\n«в том порядке, в каком тыкали» — нет.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"Alert","kind":"function","signature":"function Alert({\\n className,\\n variant,\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof alertVariants>)","summary":"","params":[],"examplesCount":0,"topics":["overview","form-layout"],"sourcePath":"src/components/alert/variants/base/alert-base.tsx","entries":[".","./alert"],"package":"@reformer/ui-kit","usage":6},{"name":"alertBasePropsSchema","kind":"const","signature":"export const alertBasePropsSchema","summary":"Props-схема презентационного `Alert` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Alert` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Alert\'` — каноническое имя в реестре renderer-json.\\nРеальные сериализуемые пропсы: `className` + cva-`variant` (default | destructive).","params":[],"examplesCount":0,"sourcePath":"src/components/alert/variants/base/alert-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AlertDescription","kind":"function","signature":"function AlertDescription({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/alert/variants/base/alert-base.tsx","entries":[".","./alert"],"package":"@reformer/ui-kit"},{"name":"AlertDialog","kind":"function","signature":"function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogAction","kind":"function","signature":"function AlertDialogAction({\\n className,\\n variant = \'default\',\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &\\n Pick<React.ComponentProps<typeof Button>, \'variant\' | \'size\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"alertDialogBasePropsSchema","kind":"const","signature":"export const alertDialogBasePropsSchema","summary":"Props-схема AlertDialog (Radix AlertDialog.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/размер — на AlertDialogContent).","description":"Props-схема AlertDialog (Radix AlertDialog.Root) — контекст-провайдер без DOM, поэтому НЕ несёт\\nclassName (стили/размер — на AlertDialogContent). AlertDialog всегда модальный (Radix убирает `modal`),\\nпоэтому такого пропа нет. Управляемое состояние (open/onOpenChange) — runtime, не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AlertDialogCancel","kind":"function","signature":"function AlertDialogCancel({\\n className,\\n variant = \'outline\',\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &\\n Pick<React.ComponentProps<typeof Button>, \'variant\' | \'size\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogContent","kind":"function","signature":"function AlertDialogContent({\\n className,\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {\\n size?: \'default\' | \'sm\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogDescription","kind":"function","signature":"function AlertDialogDescription({\\n className,\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogFooter","kind":"function","signature":"function AlertDialogFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogHeader","kind":"function","signature":"function AlertDialogHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogMedia","kind":"function","signature":"function AlertDialogMedia({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogOverlay","kind":"function","signature":"function AlertDialogOverlay({\\n className,\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogPortal","kind":"function","signature":"function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogTitle","kind":"function","signature":"function AlertDialogTitle({\\n className,\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertDialogTrigger","kind":"function","signature":"function AlertDialogTrigger({\\n ...props\\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert-dialog/variants/base/alert-dialog-base.tsx","entries":[".","./alert-dialog"],"package":"@reformer/ui-kit"},{"name":"AlertTitle","kind":"function","signature":"function AlertTitle({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/alert/variants/base/alert-base.tsx","entries":[".","./alert"],"package":"@reformer/ui-kit"},{"name":"alertVariants","kind":"const","signature":"const alertVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/alert/variants/base/alert-base.tsx","entries":[".","./alert"],"package":"@reformer/ui-kit"},{"name":"ArrayComponentProps","kind":"interface","signature":"export interface ArrayComponentProps {\\n /** Отрендеренные элементы массива в порядке следования. */\\n items?: ArrayItemSlot[];\\n /** Добавить элемент (значение нового элемента резолвит вызывающая сторона). */\\n onAdd?: () => void;\\n /** Удалить элемент по индексу. */\\n onRemove?: (index: number) => void;\\n /** Переместить элемент (реордер). */\\n onMove?: (from: number, to: number) => void;\\n}","summary":"Общие props компонента-рендерера массива: элементы + мутации.","description":"Общие props компонента-рендерера массива: элементы + мутации.","params":[],"examplesCount":0,"sourcePath":"src/lib/array-slot.ts","entries":[".","./list"],"package":"@reformer/ui-kit"},{"name":"ArrayItemSlot","kind":"interface","signature":"export interface ArrayItemSlot {\\n /** Стабильный React-ключ элемента. */\\n key: Key;\\n /** Живой индекс в массиве — для `onRemove(index)` / `onMove(index, …)`. */\\n index: number;\\n /** Данные элемента — для меток вида `itemLabel(model, index)`. */\\n model?: unknown;\\n /** Отрендеренное содержимое элемента. */\\n children: ReactNode;\\n}","summary":"Один готовый к отрисовке элемент массива.","description":"Один готовый к отрисовке элемент массива.","params":[],"examplesCount":0,"sourcePath":"src/lib/array-slot.ts","entries":[".","./list"],"package":"@reformer/ui-kit"},{"name":"AspectRatio","kind":"function","signature":"function AspectRatio({ ...props }: React.ComponentProps<typeof AspectRatioPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/aspect-ratio/variants/base/aspect-ratio-base.tsx","entries":[".","./aspect-ratio"],"package":"@reformer/ui-kit"},{"name":"aspectRatioBasePropsSchema","kind":"const","signature":"export const aspectRatioBasePropsSchema","summary":"Props-схема AspectRatio (Radix AspectRatio.Root) — держит контент в заданной пропорции.","description":"Props-схема AspectRatio (Radix AspectRatio.Root) — держит контент в заданной пропорции.","params":[],"examplesCount":0,"sourcePath":"src/components/aspect-ratio/variants/base/aspect-ratio-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundary","kind":"const","signature":"const AsyncBoundary","summary":"","params":[],"examplesCount":0,"topics":["overview","layout-and-buttons","troubleshooting","form-layout"],"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit","usage":29},{"name":"AsyncBoundaryEmpty","kind":"function","signature":"function AsyncBoundaryEmpty({\\n className,\\n title = \'Нет данных\',\\n description,\\n icon,\\n action,\\n ...props\\n}: AsyncBoundaryEmptyProps)","summary":"Блок «данные загрузились, но их нет» поверх примитивов `Empty*`.","description":"Блок «данные загрузились, но их нет» поверх примитивов `Empty*`.\\n\\nОтдельный от ошибки экран: пустой результат — это успех, а не сбой, объявлять его\\nчерез `role=\\"alert\\"` нельзя.","params":[["props","- См. {@link AsyncBoundaryEmptyProps}."]],"returns":"Разметку пустого состояния.","example":"Пустой список после успешной загрузки\\n```tsx\\n<AsyncBoundary.Empty when={items.length === 0}>\\n<AsyncBoundaryEmpty description=\\"Заявок пока нет\\" action={<Button>Создать</Button>} />\\n</AsyncBoundary.Empty>\\n```","examplesCount":2,"topics":["layout-and-buttons"],"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryEmptyProps","kind":"interface","signature":"export interface AsyncBoundaryEmptyProps extends Omit<React.ComponentProps<\'div\'>, \'title\'> {\\n /** Заголовок. @default \'Нет данных\' */\\n title?: React.ReactNode;\\n /** Пояснение под заголовком. */\\n description?: React.ReactNode;\\n /** Иконка в медальоне над заголовком. */\\n icon?: React.ReactNode;\\n /** Действие под текстом — например кнопка «Создать». */\\n action?: React.ReactNode;\\n}","summary":"Props {@link AsyncBoundaryEmpty}.","description":"Props {@link AsyncBoundaryEmpty}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryError","kind":"function","signature":"function AsyncBoundaryError({\\n className,\\n error,\\n title = \'Ошибка загрузки\',\\n onRetry,\\n retryLabel = \'Повторить\',\\n ...props\\n}: AsyncBoundaryErrorProps)","summary":"Блок ошибки — карточка с иконкой, заголовком, текстом ошибки и кнопкой повтора.","description":"Блок ошибки — карточка с иконкой, заголовком, текстом ошибки и кнопкой повтора.\\n\\nОбъявляется настойчиво (`role=\\"alert\\"` + `aria-live=\\"assertive\\"`): потеря данных должна\\nпрервать чтение, иначе пользователь продолжит работать с пустым экраном.","params":[["props","- См. {@link AsyncBoundaryErrorProps}."]],"returns":"Разметку блока ошибки.","example":"Внутри слота, с доступом к самой ошибке\\n```tsx\\n<AsyncBoundary.Error>\\n{({ error, retry }) => <AsyncBoundaryError error={error} onRetry={retry} />}\\n</AsyncBoundary.Error>\\n```","examplesCount":2,"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryErrorProps","kind":"interface","signature":"export interface AsyncBoundaryErrorProps extends Omit<React.ComponentProps<\'div\'>, \'title\'> {\\n /** Текст ошибки под заголовком. */\\n error?: React.ReactNode;\\n /** Заголовок блока. @default \'Ошибка загрузки\' */\\n title?: React.ReactNode;\\n /** Колбэк повтора. Без него кнопка не рендерится. */\\n onRetry?: () => void;\\n /** Подпись кнопки повтора. @default \'Повторить\' */\\n retryLabel?: React.ReactNode;\\n}","summary":"Props {@link AsyncBoundaryError}.","description":"Props {@link AsyncBoundaryError}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryLoading","kind":"function","signature":"function AsyncBoundaryLoading({\\n className,\\n title = \'Загрузка данных...\',\\n subtitle = \'Пожалуйста, подождите\',\\n ...props\\n}: AsyncBoundaryLoadingProps)","summary":"Блок загрузки — центрированный спиннер с заголовком и подзаголовком.","description":"Блок загрузки — центрированный спиннер с заголовком и подзаголовком.\\n\\nОбъявляется вежливо (`role=\\"status\\"` + `aria-live=\\"polite\\"`): появление индикатора\\nне должно прерывать чтение текущего контента скринридером.","params":[["props","- См. {@link AsyncBoundaryLoadingProps}."]],"returns":"Разметку блока загрузки.","example":"Собственный текст внутри слота\\n```tsx\\n<AsyncBoundary.Loading>\\n<AsyncBoundaryLoading title=\\"Загружаем заявку…\\" subtitle={null} />\\n</AsyncBoundary.Loading>\\n```","examplesCount":2,"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryLoadingProps","kind":"interface","signature":"export interface AsyncBoundaryLoadingProps extends Omit<React.ComponentProps<\'div\'>, \'title\'> {\\n /** Основной текст. @default \'Загрузка данных...\' */\\n title?: React.ReactNode;\\n /** Вспомогательный текст под спиннером. @default \'Пожалуйста, подождите\' */\\n subtitle?: React.ReactNode;\\n}","summary":"Props {@link AsyncBoundaryLoading}.","description":"Props {@link AsyncBoundaryLoading}.","params":[],"examplesCount":0,"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"AsyncBoundaryProps","kind":"interface","signature":"export interface AsyncBoundaryProps<T = unknown> {\\n /**\\n * Загрузчик. Получает `AbortSignal` — прокиньте его в `fetch`. Наличие этого пропа\\n * включает self-managed режим: статус, отмена и повтор берутся на себя компонентом.\\n */\\n load?: (signal: AbortSignal) => Promise<T>;\\n /** Ключ перезапуска: при изменении стартует новая загрузка (обычно id записи). */\\n loadKey?: unknown;\\n /** `false` → загрузка не стартует, состояние `idle`. Режим создания записи. @default true */\\n enabled?: boolean;\\n /** Побочный эффект после успеха — например `form.patchValue(data)`. */\\n onSuccess?: (data: T) => void;\\n /** Побочный эффект после ошибки — логирование, тост. */\\n onError?: (error: React.ReactNode) => void;\\n /** Преобразование отказа промиса в отображаемый текст. По умолчанию — сообщение `Error`. */\\n toError?: (e: unknown) => React.ReactNode;\\n /** Текущее состояние. Обязателен в controlled-режиме (когда `load` не передан). */\\n status?: AsyncStatus;\\n /** Текст ошибки — попадает в блок ошибки и в render-функцию `errorSlot`. */\\n error?: React.ReactNode | null;\\n /** Повтор загрузки. Без него кнопка «Повторить» не рендерится. */\\n onRetry?: () => void;\\n /** Фоновое обновление: контент остаётся на экране, регион помечается `aria-busy`. */\\n refreshing?: boolean;\\n /** Не показывать блок загрузки первые N мс — гасит вспышку спиннера. @default 0 */\\n delayMs?: number;\\n /** Заголовок блока загрузки. */\\n loadingTitle?: React.ReactNode;\\n /** Подзаголовок блока загрузки. */\\n loadingSubtitle?: React.ReactNode;\\n /** Заголовок блока ошибки. */\\n errorTitle?: React.ReactNode;\\n /** Подпись кнопки повтора. */\\n retryLabel?: React.ReactNode;\\n /** Полная замена блока загрузки — например скелетон вместо спиннера. */\\n loadingSlot?: React.ReactNode;\\n /** Полная замена блока ошибки. Render-функция получает `error` / `retry` / `canRetry`. */\\n errorSlot?:\\n | React.ReactNode\\n | ((props: AsyncBoundaryErrorRenderProps<React.ReactNode>) => React.ReactNode);\\n /** Контент, видимый при `status === \'ready\'` и `\'idle\'`. */\\n children?: React.ReactNode;\\n /** Класс региона-обёртки. */\\n className?: string;\\n}","summary":"Props {@link AsyncBoundary}.","description":"Props {@link AsyncBoundary}.\\n\\nДва режима, взаимоисключающих: **self-managed** (передан `load` — компонент грузит\\nданные сам) и **controlled** (`load` не передан — состояние приходит через `status`).","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/async-boundary/variants/base/async-boundary-base.tsx","entries":[".","./async-boundary"],"package":"@reformer/ui-kit"},{"name":"Attachment","kind":"function","signature":"function Attachment({\\n className,\\n state = \'done\',\\n size = \'default\',\\n orientation = \'horizontal\',\\n ...props\\n}: React.ComponentProps<\'div\'> &\\n VariantProps<typeof attachmentVariants> & {\\n state?: \'idle\' | \'uploading\' | \'processing\' | \'error\' | \'done\';\\n })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentAction","kind":"function","signature":"function AttachmentAction({\\n className,\\n variant,\\n size = \'icon-xs\',\\n ...props\\n}: React.ComponentProps<typeof Button>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentActions","kind":"function","signature":"function AttachmentActions({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"attachmentBasePropsSchema","kind":"const","signature":"export const attachmentBasePropsSchema","summary":"Props-схема Attachment (корневой `<div data-slot=\\"attachment\\">`) — презентационный чип/превью прикреплённого файла.","description":"Props-схема Attachment (корневой `<div data-slot=\\"attachment\\">`) — презентационный\\nчип/превью прикреплённого файла. Root рендерит DOM-элемент и пробрасывает className,\\nпоэтому сериализуемые пропсы — только визуальные enum\'ы (state/size/orientation) + className;\\nконтент задаётся суб-компонентами (Media/Content/Title/…), а не пропсами Root.","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AttachmentContent","kind":"function","signature":"function AttachmentContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentDescription","kind":"function","signature":"function AttachmentDescription({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentGroup","kind":"function","signature":"function AttachmentGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentMedia","kind":"function","signature":"function AttachmentMedia({\\n className,\\n variant = \'icon\',\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof attachmentMediaVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"attachmentMediaVariants","kind":"const","signature":"const attachmentMediaVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentTitle","kind":"function","signature":"function AttachmentTitle({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"AttachmentTrigger","kind":"function","signature":"function AttachmentTrigger({\\n className,\\n asChild = false,\\n type,\\n ...props\\n}: React.ComponentProps<\'button\'> & {\\n asChild?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"attachmentVariants","kind":"const","signature":"const attachmentVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/attachment/variants/base/attachment-base.tsx","entries":[".","./attachment"],"package":"@reformer/ui-kit"},{"name":"Avatar","kind":"function","signature":"function Avatar({\\n className,\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\\n size?: \'default\' | \'sm\' | \'lg\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit","usage":1},{"name":"AvatarBadge","kind":"function","signature":"function AvatarBadge({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit"},{"name":"avatarBasePropsSchema","kind":"const","signature":"export const avatarBasePropsSchema","summary":"Props-схема `Avatar` — единый источник `api`/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема `Avatar` — единый источник `api`/props (reformer-doc) и валидации\\n`componentProps` (renderer-json). `Avatar` — обёртка над Radix `Avatar.Root` (compound-набор),\\nне form-control: нет seam (`value`/`onChange`/`onBlur`/`disabled`), поэтому нет `x-runtimeProps`.\\nИзображение/фолбэк — под-компоненты (AvatarImage/AvatarFallback) из `children[]` схемы рендера,\\nа не пропсы Root: `src`/`alt` тут не фигурируют. Сериализуемые пропсы самого Root — `className`\\nи custom-размер `size`.\\n\\n`additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'Avatar\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"AvatarFallback","kind":"function","signature":"function AvatarFallback({\\n className,\\n ...props\\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit"},{"name":"AvatarGroup","kind":"function","signature":"function AvatarGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit"},{"name":"AvatarGroupCount","kind":"function","signature":"function AvatarGroupCount({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit"},{"name":"AvatarImage","kind":"function","signature":"function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/avatar/variants/base/avatar-base.tsx","entries":[".","./avatar"],"package":"@reformer/ui-kit"},{"name":"Badge","kind":"function","signature":"function Badge({\\n className,\\n variant = \'default\',\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'span\'> & VariantProps<typeof badgeVariants> & { asChild?: boolean })","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/badge/variants/base/badge-base.tsx","entries":[".","./badge"],"package":"@reformer/ui-kit"},{"name":"badgeBasePropsSchema","kind":"const","signature":"export const badgeBasePropsSchema","summary":"Props-схема презентационного `Badge` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Badge` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Badge\'` — каноническое имя в реестре renderer-json.\\nРеальные сериализуемые пропсы: `className` + cva-`variant`\\n(default | secondary | destructive | outline | ghost | link). `asChild` не сериализуем.","params":[],"examplesCount":0,"sourcePath":"src/components/badge/variants/base/badge-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"badgeVariants","kind":"const","signature":"const badgeVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/badge/variants/base/badge-base.tsx","entries":[".","./badge"],"package":"@reformer/ui-kit"},{"name":"Box","kind":"function","signature":"export function Box({ className, children }: BoxProps): ReactNode","summary":"Box - базовый контейнер-обёртка.","description":"Box - базовый контейнер-обёртка.\\n\\nПростой `<div>` для группировки элементов в `RenderSchema`. Используйте\\n`className` для настройки layout через atomic CSS (Tailwind).","params":[],"example":"Вертикальный список полей в RenderSchema (M1: лист = `value` + `component`)\\n```typescript\\nimport { Box, Input, InputPassword } from \'@reformer/ui-kit\';\\n\\n{\\ncomponent: Box,\\ncomponentProps: { className: \'flex flex-col gap-4\' },\\nchildren: [\\n{ value: model.$.email, component: InputField },\\n{ value: model.$.password, component: InputPasswordField },\\n],\\n}\\n```","examplesCount":2,"topics":["overview","form-field-integration","form-wizard","form-array-section","imperative-handles","form-layout"],"sourcePath":"src/components/box/variants/base/box-base.tsx","entries":[".","./box"],"package":"@reformer/ui-kit","usage":40},{"name":"boxBasePropsSchema","kind":"const","signature":"export const boxBasePropsSchema","summary":"Props-схема DSL-контейнера `Box` — единый источник `api`/props (reformer-doc) и валидации `componentProps` в renderer-json.","description":"Props-схема DSL-контейнера `Box` — единый источник `api`/props (reformer-doc) и\\nвалидации `componentProps` в renderer-json. `Box` — не form-control (нет seam/field/адаптера),\\nпоэтому в схеме нет `x-runtimeProps`: единственный сериализуемый проп — `className`.\\n\\n`children` в схеме НЕ фигурирует: дочерние ноды приходят из `children[]` схемы рендера,\\nа не из `componentProps`. `additionalProperties: false` ловит опечатки в DSL.\\n\\n`x-registryName: \'Box\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/box/variants/base/box-base.props.ts","entries":[".","./meta","./box"],"package":"@reformer/ui-kit"},{"name":"BoxProps","kind":"interface","signature":"export interface BoxProps {\\n /** CSS класс для стилизации */\\n className?: string;\\n /** Дочерние элементы */\\n children?: ReactNode;\\n}","summary":"Props компонента Box","description":"Props компонента Box","params":[],"examplesCount":0,"sourcePath":"src/components/box/variants/base/box-base.tsx","entries":[".","./box"],"package":"@reformer/ui-kit"},{"name":"Breadcrumb","kind":"function","signature":"function Breadcrumb({ ...props }: React.ComponentProps<\'nav\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"breadcrumbBasePropsSchema","kind":"const","signature":"export const breadcrumbBasePropsSchema","summary":"Props-схема Breadcrumb (Root) — семантический `<nav aria-label=\\"breadcrumb\\">`.","description":"Props-схема Breadcrumb (Root) — семантический `<nav aria-label=\\"breadcrumb\\">`.\\nПрезентационный compound-контейнер без Radix-примитива и без form-состояния: Root\\nлишь оборачивает список хлебных крошек. Своих enum/boolean/number-пропсов у него нет,\\nпоэтому единственный статический сериализуемый проп — className (пробрасывается в `<nav>`).","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbEllipsis","kind":"function","signature":"function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbItem","kind":"function","signature":"function BreadcrumbItem({ className, ...props }: React.ComponentProps<\'li\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbLink","kind":"function","signature":"function BreadcrumbLink({\\n asChild,\\n className,\\n ...props\\n}: React.ComponentProps<\'a\'> & {\\n asChild?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbList","kind":"function","signature":"function BreadcrumbList({ className, ...props }: React.ComponentProps<\'ol\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbPage","kind":"function","signature":"function BreadcrumbPage({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"BreadcrumbSeparator","kind":"function","signature":"function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<\'li\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/breadcrumb/variants/base/breadcrumb-base.tsx","entries":[".","./breadcrumb"],"package":"@reformer/ui-kit"},{"name":"Bubble","kind":"function","signature":"function Bubble({\\n variant = \'default\',\\n align = \'start\',\\n className,\\n ...props\\n}: React.ComponentProps<\'div\'> &\\n VariantProps<typeof bubbleVariants> & {\\n align?: \'start\' | \'end\';\\n })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/bubble/variants/base/bubble-base.tsx","entries":[".","./bubble"],"package":"@reformer/ui-kit"},{"name":"bubbleBasePropsSchema","kind":"const","signature":"export const bubbleBasePropsSchema","summary":"Props-схема Bubble (shadcn AI-примитив пузыря сообщения чата) — Root рендерит <div> и пробрасывает className.","description":"Props-схема Bubble (shadcn AI-примитив пузыря сообщения чата) — Root рендерит <div> и\\nпробрасывает className. Статические cva-пропсы: variant (оформление) и align (сторона).","params":[],"examplesCount":0,"sourcePath":"src/components/bubble/variants/base/bubble-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"BubbleContent","kind":"function","signature":"function BubbleContent({\\n asChild = false,\\n className,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n asChild?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/bubble/variants/base/bubble-base.tsx","entries":[".","./bubble"],"package":"@reformer/ui-kit"},{"name":"BubbleGroup","kind":"function","signature":"function BubbleGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/bubble/variants/base/bubble-base.tsx","entries":[".","./bubble"],"package":"@reformer/ui-kit"},{"name":"BubbleReactions","kind":"function","signature":"function BubbleReactions({\\n side = \'bottom\',\\n align = \'end\',\\n className,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n align?: \'start\' | \'end\';\\n side?: \'top\' | \'bottom\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/bubble/variants/base/bubble-base.tsx","entries":[".","./bubble"],"package":"@reformer/ui-kit"},{"name":"Button","kind":"function","signature":"function Button({\\n className,\\n variant = \'default\',\\n size = \'default\',\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'button\'> &\\n VariantProps<typeof buttonVariants> & {\\n asChild?: boolean;\\n })","summary":"","params":[],"examplesCount":0,"topics":["overview","layout-and-buttons","form-field-integration","troubleshooting","form-layout"],"sourcePath":"src/components/button/variants/base/button-base.tsx","entries":[".","./button"],"package":"@reformer/ui-kit","usage":43},{"name":"buttonBasePropsSchema","kind":"const","signature":"export const buttonBasePropsSchema","summary":"Props-схема презентационного `Button` — единый источник api/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема презентационного `Button` — единый источник api/props (reformer-doc) и\\nвалидации `componentProps` (renderer-json). `Button` — не form-control (нет seam/field/адаптера),\\nпоэтому в схеме нет `x-runtimeProps`. `variant`/`size` — значения cva-конфига (`buttonVariants`),\\nдефолты из `defaultVariants`.\\n\\n`children` (текст/иконки) приходят из `children[]` схемы рендера, а не из `componentProps`.\\n`additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'Button\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/button/variants/base/button-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ButtonGroup","kind":"function","signature":"function ButtonGroup({\\n className,\\n orientation,\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof buttonGroupVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/button-group/variants/base/button-group-base.tsx","entries":[".","./button-group"],"package":"@reformer/ui-kit"},{"name":"buttonGroupBasePropsSchema","kind":"const","signature":"export const buttonGroupBasePropsSchema","summary":"Props-схема презентационного `ButtonGroup` — единый источник api/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема презентационного `ButtonGroup` — единый источник api/props (reformer-doc) и\\nвалидации `componentProps` (renderer-json). `ButtonGroup` — не form-control (нет seam/field/адаптера),\\nпоэтому в схеме нет `x-runtimeProps`. `orientation` — значение cva-конфига (`buttonGroupVariants`),\\nдефолт из `defaultVariants`.\\n\\n`children` (compound: ButtonGroupText / ButtonGroupSeparator / кнопки) приходят из `children[]`\\nсхемы рендера, а не из `componentProps`. `additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'ButtonGroup\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/button-group/variants/base/button-group-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ButtonGroupSeparator","kind":"function","signature":"function ButtonGroupSeparator({\\n className,\\n orientation = \'vertical\',\\n ...props\\n}: React.ComponentProps<typeof Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/button-group/variants/base/button-group-base.tsx","entries":[".","./button-group"],"package":"@reformer/ui-kit"},{"name":"ButtonGroupText","kind":"function","signature":"function ButtonGroupText({\\n className,\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n asChild?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/button-group/variants/base/button-group-base.tsx","entries":[".","./button-group"],"package":"@reformer/ui-kit"},{"name":"buttonGroupVariants","kind":"const","signature":"const buttonGroupVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/button-group/variants/base/button-group-base.tsx","entries":[".","./button-group"],"package":"@reformer/ui-kit"},{"name":"buttonVariants","kind":"const","signature":"const buttonVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/button/variants/base/button-base.tsx","entries":[".","./button"],"package":"@reformer/ui-kit"},{"name":"Calendar","kind":"function","signature":"function Calendar({\\n className,\\n classNames,\\n showOutsideDays = true,\\n captionLayout = \'label\',\\n buttonVariant = \'ghost\',\\n formatters,\\n components,\\n ...props\\n}: React.ComponentProps<typeof DayPicker> & {\\n buttonVariant?: React.ComponentProps<typeof Button>[\'variant\'];\\n})","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/calendar/variants/base/calendar-base.tsx","entries":["./calendar"],"package":"@reformer/ui-kit"},{"name":"CalendarBaseField","kind":"const","signature":"export const CalendarBaseField","summary":"Field-версия single-date Calendar: pure Calendar(mode=single) + {@link dateAdapter} (`selected`/`onSelect` ↔ `value: Date | null`).","description":"Field-версия single-date Calendar: pure Calendar(mode=single) + {@link dateAdapter}\\n(`selected`/`onSelect` ↔ `value: Date | null`). HOC отбрасывает `control` (renderer-путь).","params":[],"examplesCount":0,"sourcePath":"src/components/calendar/variants/base/calendar-base.field.tsx","entries":["./calendar"],"package":"@reformer/ui-kit"},{"name":"calendarBasePropsSchema","kind":"const","signature":"export const calendarBasePropsSchema","summary":"Props-схема Calendar (field-версия single-date) — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Calendar (field-версия single-date) — единый источник `api.controls[]` (reformer-doc)\\nи DSL-валидации `componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`value`/`onChange` — seam (маппятся адаптером на `selected`/`onSelect`), поэтому в `x-runtimeProps`,\\nа не в `properties`. `x-registryName: \'Calendar\'` — на этот вариант смотрит алиас `CalendarField`.","params":[],"examplesCount":0,"sourcePath":"src/components/calendar/variants/base/calendar-base.props.ts","entries":["./meta","./calendar"],"package":"@reformer/ui-kit"},{"name":"CalendarDayButton","kind":"function","signature":"function CalendarDayButton({\\n className,\\n day,\\n modifiers,\\n ...props\\n}: React.ComponentProps<typeof DayButton>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/calendar/variants/base/calendar-base.tsx","entries":["./calendar"],"package":"@reformer/ui-kit"},{"name":"CalendarField","kind":"const","signature":"export const CalendarBaseField","summary":"Field-версия single-date Calendar: pure Calendar(mode=single) + {@link dateAdapter} (`selected`/`onSelect` ↔ `value: Date | null`).","description":"Field-версия single-date Calendar: pure Calendar(mode=single) + {@link dateAdapter}\\n(`selected`/`onSelect` ↔ `value: Date | null`). HOC отбрасывает `control` (renderer-путь).","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/calendar/variants/base/calendar-base.field.tsx","entries":["./calendar"],"package":"@reformer/ui-kit"},{"name":"Card","kind":"function","signature":"function Card({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["overview","layout-and-buttons","form-layout"],"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"CardAction","kind":"function","signature":"function CardAction({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"cardBasePropsSchema","kind":"const","signature":"export const cardBasePropsSchema","summary":"Props-схема презентационного `Card` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Card` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Card\'` — каноническое имя в реестре renderer-json.\\nCard — чистый `ComponentProps<\'div\'>` без cva/Radix: единственный сериализуемый проп — `className`.","params":[],"examplesCount":0,"sourcePath":"src/components/card/variants/base/card-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"CardContent","kind":"function","signature":"function CardContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"CardDescription","kind":"function","signature":"function CardDescription({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"CardFooter","kind":"function","signature":"function CardFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"CardHeader","kind":"function","signature":"function CardHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"CardTitle","kind":"function","signature":"function CardTitle({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/card/variants/base/card-base.tsx","entries":[".","./card"],"package":"@reformer/ui-kit"},{"name":"Carousel","kind":"function","signature":"function Carousel({\\n orientation = \'horizontal\',\\n opts,\\n setApi,\\n plugins,\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<\'div\'> & CarouselProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"CarouselApi","kind":"type","signature":"type CarouselApi = UseEmblaCarouselType[1];","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"carouselBasePropsSchema","kind":"const","signature":"export const carouselBasePropsSchema","summary":"Props-схема Carousel (embla).","description":"Props-схема Carousel (embla). Инлайн-конфиг (opts/plugins/setApi) несериализуем — не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"CarouselContent","kind":"function","signature":"function CarouselContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"CarouselItem","kind":"function","signature":"function CarouselItem({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"CarouselNext","kind":"function","signature":"function CarouselNext({\\n className,\\n variant = \'outline\',\\n size = \'icon\',\\n ...props\\n}: React.ComponentProps<typeof Button>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"CarouselPrevious","kind":"function","signature":"function CarouselPrevious({\\n className,\\n variant = \'outline\',\\n size = \'icon\',\\n ...props\\n}: React.ComponentProps<typeof Button>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/carousel/variants/base/carousel-base.tsx","entries":["./carousel"],"package":"@reformer/ui-kit"},{"name":"chartBasePropsSchema","kind":"const","signature":"export const chartBasePropsSchema","summary":"Props-схема Chart (Root = ChartContainer, обёртка recharts ResponsiveContainer).","description":"Props-схема Chart (Root = ChartContainer, обёртка recharts ResponsiveContainer). Рендерит\\nреальный <div className={cn(..., className)} {...props}> — поэтому несёт className. Остальные\\nпропсы (config, initialDimension, children) — несериализуемые объекты/JSX, в статическую схему\\nне попадают. Enum/boolean/number-пропсов у Root нет — схема минимальна.","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ChartConfig","kind":"type","signature":"export type ChartConfig = Record<\\n string,\\n {\\n label?: React.ReactNode;\\n icon?: React.ComponentType;\\n } & (\\n | { color?: string; theme?: never }\\n | { color?: never; theme: Record<keyof typeof THEMES, string> }\\n )\\n>;","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartContainer","kind":"function","signature":"function ChartContainer({\\n id,\\n className,\\n children,\\n config,\\n initialDimension = INITIAL_DIMENSION,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n config: ChartConfig;\\n children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>[\'children\'];\\n initialDimension?: {\\n width: number;\\n height: number;\\n };\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartLegend","kind":"const","signature":"const ChartLegend","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartLegendContent","kind":"function","signature":"function ChartLegendContent({\\n className,\\n hideIcon = false,\\n payload,\\n verticalAlign = \'bottom\',\\n nameKey,\\n}: React.ComponentProps<\'div\'> & {\\n hideIcon?: boolean;\\n nameKey?: string;\\n} & RechartsPrimitive.DefaultLegendContentProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartStyle","kind":"const","signature":"const ChartStyle","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartTooltip","kind":"const","signature":"const ChartTooltip","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"ChartTooltipContent","kind":"function","signature":"function ChartTooltipContent({\\n active,\\n payload,\\n className,\\n indicator = \'dot\',\\n hideLabel = false,\\n hideIndicator = false,\\n label,\\n labelFormatter,\\n labelClassName,\\n formatter,\\n color,\\n nameKey,\\n labelKey,\\n}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\\n React.ComponentProps<\'div\'> & {\\n hideLabel?: boolean;\\n hideIndicator?: boolean;\\n indicator?: \'line\' | \'dot\' | \'dashed\';\\n nameKey?: string;\\n labelKey?: string;\\n } & Omit<\\n RechartsPrimitive.DefaultTooltipContentProps<TooltipValueType, TooltipNameType>,\\n \'accessibilityLayer\'\\n >)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"Checkbox","kind":"function","signature":"function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields","form-field-integration","troubleshooting","form-array-section"],"sourcePath":"src/components/checkbox/variants/base/checkbox-base.tsx","entries":[".","./checkbox"],"package":"@reformer/ui-kit","usage":3},{"name":"CheckboxBaseField","kind":"const","signature":"export const CheckboxBaseField","summary":"Field-версия Checkbox: pure Checkbox + подпись справа, привязка через `checkedAdapter` (`checked` / `onCheckedChange`, boolean).","description":"Field-версия Checkbox: pure Checkbox + подпись справа, привязка через `checkedAdapter`\\n(`checked` / `onCheckedChange`, boolean). Экспортируется как алиас `CheckboxField`.","params":[],"examplesCount":0,"sourcePath":"src/components/checkbox/variants/base/checkbox-base.field.tsx","entries":[".","./checkbox"],"package":"@reformer/ui-kit"},{"name":"checkboxBasePropsSchema","kind":"const","signature":"export const checkboxBasePropsSchema","summary":"Props-схема Checkbox — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Checkbox — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `x-registryName: \'Checkbox\'` — на этот вариант смотрит алиас\\n`CheckboxField`.\\n\\n`label` объявлен и здесь (не только во враппере): для inline-контрола подпись рендерит САМ\\nfield-компонент (FormField верхнюю подпись подавляет), поэтому она приходит как `componentProps.label`.\\n`value`/`onChange` переопределяют seam под boolean-контракт чекбокса.","params":[],"examplesCount":0,"sourcePath":"src/components/checkbox/variants/base/checkbox-base.props.ts","entries":[".","./meta","./checkbox"],"package":"@reformer/ui-kit"},{"name":"CheckboxField","kind":"const","signature":"export const CheckboxBaseField","summary":"Field-версия Checkbox: pure Checkbox + подпись справа, привязка через `checkedAdapter` (`checked` / `onCheckedChange`, boolean).","description":"Field-версия Checkbox: pure Checkbox + подпись справа, привязка через `checkedAdapter`\\n(`checked` / `onCheckedChange`, boolean). Экспортируется как алиас `CheckboxField`.","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields","form-field-integration","troubleshooting","form-wizard"],"sourcePath":"src/components/checkbox/variants/base/checkbox-base.field.tsx","entries":[".","./checkbox"],"package":"@reformer/ui-kit","usage":35},{"name":"CheckboxWithLabel","kind":"function","signature":"function CheckboxWithLabel({\\n label,\\n id,\\n className,\\n \'aria-labelledby\': ariaLabelledBy,\\n ...props\\n}: CheckboxWithLabelProps)","summary":"Inline-раскладка чекбокса: сам рисует подпись СПРАВА от контрола, обёрнутую в `<label htmlFor>`, потому что `FormField` для inline-контролов верхнюю подпись подавляет (маркер `reformerLayout`).","description":"Inline-раскладка чекбокса: сам рисует подпись СПРАВА от контрола, обёрнутую в `<label htmlFor>`,\\nпотому что `FormField` для inline-контролов верхнюю подпись подавляет (маркер `reformerLayout`).\\n\\n`data-testid`/`aria-*`/`checked`/`onCheckedChange` уходят на `CheckboxPrimitive.Root` (button\\nrole=checkbox), НЕ на wrapper и НЕ на скрытый bubble-input. Доступное имя даёт связанная `<label>`\\n(htmlFor↔id), поэтому висячий `aria-labelledby` (ids.labelId от FormField — верхняя подпись не\\nрендерится) сбрасываем, когда подпись есть.","params":[],"examplesCount":0,"sourcePath":"src/components/checkbox/variants/base/checkbox-base.field.tsx","entries":[".","./checkbox"],"package":"@reformer/ui-kit"},{"name":"CheckboxWithLabelProps","kind":"interface","signature":"export interface CheckboxWithLabelProps extends React.ComponentProps<typeof Checkbox> {\\n /** Подпись справа от чекбокса (inline-раскладка). Берётся из `componentProps.label`. */\\n label?: string;\\n}","summary":"Props враппера {@link CheckboxWithLabel}: pure Checkbox + опциональная подпись справа.","description":"Props враппера {@link CheckboxWithLabel}: pure Checkbox + опциональная подпись справа.","params":[],"examplesCount":0,"sourcePath":"src/components/checkbox/variants/base/checkbox-base.field.tsx","entries":[".","./checkbox"],"package":"@reformer/ui-kit"},{"name":"checkedAdapter","kind":"const","signature":"export const checkedAdapter: FieldAdapter","summary":"Checkbox / Switch — Radix `checked` + `onCheckedChange(boolean | \'indeterminate\')`.","description":"Checkbox / Switch — Radix `checked` + `onCheckedChange(boolean | \'indeterminate\')`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"cn","kind":"function","signature":"export function cn(...inputs: ClassValue[])","summary":"Объединяет CSS-классы (`clsx` + `tailwind-merge`).","description":"Объединяет CSS-классы (`clsx` + `tailwind-merge`). Удобно для условных\\nклассов с разрешением конфликтов Tailwind: при конфликтующих классах из\\nодной семьи (`px-2` и `px-4`) побеждает последний.","params":[],"example":"Условные классы (последний `px-*` побеждает)\\n```typescript\\nimport { cn } from \'@reformer/ui-kit\';\\n\\ncn(\'px-2 py-1\', isActive && \'bg-blue-500\', \'px-4\');\\n// → \'py-1 bg-blue-500 px-4\'\\n```","examplesCount":2,"topics":["overview","layout-and-buttons","troubleshooting","form-layout"],"sourcePath":"src/lib/utils.ts","entries":["."],"package":"@reformer/ui-kit"},{"name":"Collapsible","kind":"function","signature":"function Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/collapsible/variants/base/collapsible-base.tsx","entries":[".","./collapsible"],"package":"@reformer/ui-kit","usage":6},{"name":"collapsibleBasePropsSchema","kind":"const","signature":"export const collapsibleBasePropsSchema","summary":"Props-схема презентационного `Collapsible` — единый источник api/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема презентационного `Collapsible` — единый источник api/props (reformer-doc) и\\nвалидации `componentProps` (renderer-json). `Collapsible` — обёртка над Radix `Collapsible.Root`\\n(не form-control: нет seam/field/адаптера), поэтому в схеме нет `x-runtimeProps`.\\n\\n`children` (compound: CollapsibleTrigger / CollapsibleContent) приходят из `children[]` схемы\\nрендера, а не из `componentProps`. `additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'Collapsible\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/collapsible/variants/base/collapsible-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"CollapsibleContent","kind":"function","signature":"function CollapsibleContent({\\n ...props\\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/collapsible/variants/base/collapsible-base.tsx","entries":[".","./collapsible"],"package":"@reformer/ui-kit"},{"name":"CollapsibleTrigger","kind":"function","signature":"function CollapsibleTrigger({\\n ...props\\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/collapsible/variants/base/collapsible-base.tsx","entries":[".","./collapsible"],"package":"@reformer/ui-kit"},{"name":"Combobox","kind":"const","signature":"const Combobox","summary":"Combobox (вариант `base`): управляемый поиск по опциям в Popover + Command.","description":"Combobox (вариант `base`): управляемый поиск по опциям в Popover + Command. Триггер-кнопка\\nпоказывает `label` текущего значения либо `placeholder`. Выбор опции эмитит `onChange(value)`;\\nпри `clearable` повторный клик по выбранной опции или крестик сбрасывают выбор в `null`.","params":[],"examplesCount":0,"topics":["overview","choice-fields","imperative-handles"],"sourcePath":"src/components/combobox/variants/base/combobox-base.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":2},{"name":"ComboboxBaseField","kind":"const","signature":"export const ComboboxBaseField","summary":"`exposesHandle: true` — Combobox сам реализует {@link ComboboxHandle} (useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — Combobox сам реализует {@link ComboboxHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/base/combobox-base.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"comboboxBasePropsSchema","kind":"const","signature":"export const comboboxBasePropsSchema","summary":"Props-схема Combobox (field-версия) — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Combobox (field-версия) — единый источник `api.controls[]` (reformer-doc) и\\nDSL-валидации `componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`value`/`onChange` — seam (Combobox уже value-based), поэтому в `x-runtimeProps`, а не в\\n`properties`. `x-registryName: \'Combobox\'` — на этот вариант смотрит алиас `ComboboxField`.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/base/combobox-base.props.ts","entries":["./meta","./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxField","kind":"const","signature":"export const ComboboxBaseField","summary":"`exposesHandle: true` — Combobox сам реализует {@link ComboboxHandle} (useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — Combobox сам реализует {@link ComboboxHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"topics":["overview","imperative-handles"],"sourcePath":"src/components/combobox/variants/base/combobox-base.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxHandle","kind":"interface","signature":"export interface ComboboxHandle extends FieldHandle {\\n /** Открыть popover со списком. */\\n open(): void;\\n /** Закрыть popover (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить выбранное значение в `null`. */\\n clear(): void;\\n}","summary":"Императивный handle {@link Combobox}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/ getElement на кнопке-триггере) + управление popover\'ом.","description":"Императивный handle {@link Combobox}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/\\ngetElement на кнопке-триггере) + управление popover\'ом. Достаётся из схемы:\\n`schema.node(\'city\').getRef<ComboboxHandle>().current?.open()`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/combobox/variants/base/combobox-base.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxMulti","kind":"const","signature":"const ComboboxMulti","summary":"Combobox в режиме множественного выбора (вариант `multi`): та же композиция Popover + Command + Button, что у одиночного, но со списком-чекбоксами и чипами в триггере.","description":"Combobox в режиме множественного выбора (вариант `multi`): та же композиция\\nPopover + Command + Button, что у одиночного, но со списком-чекбоксами и чипами в триггере.\\n\\nТри поведенческих отличия от одиночного варианта, и все три намеренные:\\n - выбор пункта НЕ закрывает popover — иначе отметить несколько подряд было бы нельзя;\\n - поиск НЕ сбрасывается после тогла: cmdk сам ведёт активный пункт, и сброс заставлял бы\\n список перескакивать под курсором;\\n - `onBlur` эмитится только при закрытии popover, поэтому поле дольше остаётся не-touched.\\n\\nЧипы в триггере НЕинтерактивны намеренно: интерактивный элемент внутри `button` — невалидная\\nразметка. Снять значение можно пунктом списка, сбросить всё — крестиком `clearable`, который\\n(как и у одиночного варианта) живёт ВНЕ триггера.","params":[],"examplesCount":0,"topics":["choice-fields","troubleshooting"],"sourcePath":"src/components/combobox/variants/multi/combobox-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":1},{"name":"ComboboxMultiField","kind":"const","signature":"export const ComboboxMultiField","summary":"`exposesHandle: true` — ComboboxMulti сам реализует {@link ComboboxMultiHandle} (`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — ComboboxMulti сам реализует {@link ComboboxMultiHandle}\\n(`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough),\\nбез своего baseline-handle. Привязка — общий для кита {@link multiValueAdapter}.","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/combobox/variants/multi/combobox-multi.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":3},{"name":"ComboboxMultiFieldProps","kind":"interface","signature":"export interface ComboboxMultiFieldProps {\\n value?: string[] | null;\\n onChange?: (value: string[] | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n options?: ComboboxOption[];\\n placeholder?: string;\\n searchPlaceholder?: string;\\n emptyText?: string;\\n clearable?: boolean;\\n creatable?: boolean;\\n maxItems?: number;\\n summaryThreshold?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии ComboboxMulti.","description":"Value-based контракт field-версии ComboboxMulti. Значение — `string[] | null`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт остальное в `componentProps`.\\nСлужит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/multi/combobox-multi.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxMultiHandle","kind":"interface","signature":"export interface ComboboxMultiHandle extends FieldHandle {\\n /** Открыть popover со списком. */\\n open(): void;\\n /** Закрыть popover (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить весь выбор. */\\n clear(): void;\\n}","summary":"Императивный handle {@link ComboboxMulti}: baseline {@link FieldHandle} на кнопке-триггере + управление popover\'ом.","description":"Императивный handle {@link ComboboxMulti}: baseline {@link FieldHandle} на кнопке-триггере +\\nуправление popover\'ом. Достаётся из схемы: `schema.node(\'tags\').getRef<ComboboxMultiHandle>()`.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/multi/combobox-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxMultiProps","kind":"interface","signature":"export interface ComboboxMultiProps {\\n className?: string;\\n /**\\n * Выбранные значения. Приходит массивом всегда: `multiValueAdapter` разворачивает `null` в `[]`,\\n * потому что рендер ходит по значению `.includes`/`.map`.\\n */\\n value?: string[];\\n /** Изменение выбора. Всегда получает НОВЫЙ массив — см. `multiValueAdapter`. */\\n onChange?: (value: string[]) => void;\\n /** Срабатывает при закрытии popover (снятие фокуса). */\\n onBlur?: () => void;\\n /** Список опций. */\\n options?: ComboboxOption[];\\n /** Подсказка в триггере, пока ничего не выбрано. */\\n placeholder?: string;\\n /** Подсказка в поле поиска. */\\n searchPlaceholder?: string;\\n /** Текст пустого состояния (ничего не найдено). */\\n emptyText?: string;\\n /** Показывать крестик сброса ВСЕГО выбора. */\\n clearable?: boolean;\\n /**\\n * Creatable-режим: введённое значение, не совпавшее ни с одной опцией, добавляется в выбор\\n * пунктом «Создать». Лейблом для него служит само значение.\\n */\\n creatable?: boolean;\\n /**\\n * Потолок числа выбранных: по достижении невыбранные пункты выключаются.\\n * Подсказка интерфейса, а НЕ правило формы — ограничение задавайте валидатором `maxLength(n)`.\\n */\\n maxItems?: number;\\n /** Сколько чипов показать в триггере до схлопывания в сводку. По умолчанию 3. */\\n summaryThreshold?: number;\\n disabled?: boolean;\\n /** id корневого элемента — по нему форма связывает подпись, описание и сообщение об ошибке. */\\n id?: string;\\n /** Префикс `data-testid`; на триггер + `-<value>` на каждый пункт списка. */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props компонента {@link ComboboxMulti}.","description":"Props компонента {@link ComboboxMulti}.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/multi/combobox-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"comboboxMultiPropsSchema","kind":"const","signature":"export const comboboxMultiPropsSchema","summary":"Props-схема ComboboxMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема ComboboxMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'ComboboxMulti\'` — отдельная запись каталога, а не проп `multiple` у\\n`Combobox`: тип значения другой (`string[] | null` против `string | null`), а\\n`x-runtimeProps.value` у записи ровно один. Прецедент — `FileUpload` / `FileUploadAvatar`.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/multi/combobox-multi.props.ts","entries":["./meta","./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxOption","kind":"interface","signature":"export interface ComboboxOption {\\n value: string;\\n label: string;\\n}","summary":"Опция комбобокса: `value` — хранимое значение, `label` — отображаемый и искомый текст.","description":"Опция комбобокса: `value` — хранимое значение, `label` — отображаемый и искомый текст.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/base/combobox-base.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxProps","kind":"interface","signature":"export interface ComboboxProps {\\n className?: string;\\n /** Выбранное значение (строка из `option.value`). `null` — ничего не выбрано. */\\n value?: string | null;\\n /** Обработчик выбора. При очистке (крестик / повторный клик по выбранной опции) приходит `null`. */\\n onChange?: (value: string | null) => void;\\n /** Срабатывает при закрытии popover (снятие фокуса). */\\n onBlur?: () => void;\\n /** Список опций. */\\n options?: ComboboxOption[];\\n /** Подсказка в триггере, пока ничего не выбрано. По умолчанию `\'Select an option...\'`. */\\n placeholder?: string;\\n /** Подсказка в поле поиска. По умолчанию `\'Search...\'`. */\\n searchPlaceholder?: string;\\n /** Текст пустого состояния (ничего не найдено). По умолчанию `\'No options found.\'`. */\\n emptyText?: string;\\n /** Показывать ли крестик очистки справа от значения. По умолчанию `false`. */\\n clearable?: boolean;\\n /**\\n * Creatable-режим: разрешить ввести своё значение. Когда введённый текст не совпадает точно ни с\\n * одной опцией, в списке появляется пункт «Создать «…»» — выбор эмитит введённое значение как\\n * `value` (label в триггере = само значение). По умолчанию `false`.\\n */\\n creatable?: boolean;\\n disabled?: boolean;\\n id?: string;\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props компонента {@link Combobox}.","description":"Props компонента {@link Combobox}.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/base/combobox-base.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTree","kind":"const","signature":"const ComboboxTree","summary":"Combobox с деревом (вариант `tree`): выбор одного узла — как правило файла — из иерархии.","description":"Combobox с деревом (вариант `tree`): выбор одного узла — как правило файла — из иерархии.\\n\\nТриггер показывает подпись выбранного узла, а если узел пришёл из лениво прочитанного\\nуровня и в объявленном дереве его нет — сам адрес. Для файлов это не компромисс, а то,\\nчто и нужно видеть: путь однозначен, имя файла — нет.","params":[],"examplesCount":0,"topics":["overview","choice-fields","troubleshooting"],"sourcePath":"src/components/combobox/variants/tree/combobox-tree.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":3},{"name":"ComboboxTreeField","kind":"const","signature":"export const ComboboxTreeField","summary":"`exposesHandle: true` — ComboboxTree сам реализует {@link ComboboxTreeHandle} (`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — ComboboxTree сам реализует {@link ComboboxTreeHandle}\\n(`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит\\n(passthrough), без своего baseline-handle. Привязка — общий с одиночным вариантом\\n{@link comboboxAdapter}: контракт значения у них один и тот же.","params":[],"examplesCount":0,"topics":["overview","choice-fields","layout-and-buttons","imperative-handles"],"sourcePath":"src/components/combobox/variants/tree/combobox-tree.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":3},{"name":"ComboboxTreeFieldProps","kind":"interface","signature":"export interface ComboboxTreeFieldProps {\\n value?: string | null;\\n onChange?: (value: string | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n nodes?: readonly TreeNode[];\\n loadChildren?: (node: TreeNode | null) => Promise<readonly TreeNode[]>;\\n defaultExpandedIds?: readonly string[];\\n selectable?: \'all\' | \'leaf\';\\n placeholder?: string;\\n searchPlaceholder?: string;\\n emptyText?: string;\\n clearable?: boolean;\\n maxRows?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии ComboboxTree.","description":"Value-based контракт field-версии ComboboxTree. Значение — `string | null` (адрес узла);\\nформа резолвит `value`/`onChange`/`onBlur`/`disabled`, автор задаёт остальное в\\n`componentProps`. Служит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree/combobox-tree.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTreeHandle","kind":"interface","signature":"export interface ComboboxTreeHandle extends FieldHandle {\\n /** Открыть popover с деревом. */\\n open(): void;\\n /** Закрыть popover (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить выбранное значение в `null`. */\\n clear(): void;\\n /**\\n * Перечитать уровень дерева: файл создан, удалён, переименован. `null` — верхний уровень.\\n * Действует, только пока popover открыт: закрытый Radix содержимое размонтирует, и\\n * перечитывать нечего — следующее открытие прочитает уровень заново.\\n */\\n refresh(id?: string | null): Promise<void>;\\n}","summary":"Императивный handle {@link ComboboxTree}: baseline {@link FieldHandle} на кнопке-триггере + управление popover\'ом и уровнями дерева.","description":"Императивный handle {@link ComboboxTree}: baseline {@link FieldHandle} на кнопке-триггере +\\nуправление popover\'ом и уровнями дерева.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/combobox/variants/tree/combobox-tree.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTreeMulti","kind":"const","signature":"const ComboboxTreeMulti","summary":"Combobox с деревом, множественный выбор (вариант `tree-multi`): набор узлов — как правило файлов — из иерархии.","description":"Combobox с деревом, множественный выбор (вариант `tree-multi`): набор узлов — как правило\\nфайлов — из иерархии. Значение — `string[] | null` на стороне формы (пустой выбор всегда\\n`null`, никогда `[]`) и `string[]` на стороне компонента.","params":[],"examplesCount":0,"topics":["choice-fields","troubleshooting"],"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":3},{"name":"ComboboxTreeMultiField","kind":"const","signature":"export const ComboboxTreeMultiField","summary":"`exposesHandle: true` — ComboboxTreeMulti сам реализует {@link ComboboxTreeMultiHandle} (`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — ComboboxTreeMulti сам реализует {@link ComboboxTreeMultiHandle}\\n(`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит\\n(passthrough), без своего baseline-handle. Привязка — общий для кита\\n{@link multiValueAdapter}: он же разворачивает `null` в `[]` на входе и сворачивает\\nпустой выбор обратно в `null` на выходе.","params":[],"examplesCount":0,"topics":["overview","choice-fields","layout-and-buttons","imperative-handles"],"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit","usage":3},{"name":"ComboboxTreeMultiFieldProps","kind":"interface","signature":"export interface ComboboxTreeMultiFieldProps {\\n value?: string[] | null;\\n onChange?: (value: string[] | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n nodes?: readonly TreeNode[];\\n loadChildren?: (node: TreeNode | null) => Promise<readonly TreeNode[]>;\\n defaultExpandedIds?: readonly string[];\\n selectable?: \'all\' | \'leaf\';\\n placeholder?: string;\\n searchPlaceholder?: string;\\n emptyText?: string;\\n clearable?: boolean;\\n maxItems?: number;\\n summaryThreshold?: number;\\n maxRows?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии ComboboxTreeMulti.","description":"Value-based контракт field-версии ComboboxTreeMulti. Значение — `string[] | null` (адреса\\nузлов); форма резолвит `value`/`onChange`/`onBlur`/`disabled`, автор задаёт остальное\\nв `componentProps`. Служит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.field.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTreeMultiHandle","kind":"interface","signature":"export interface ComboboxTreeMultiHandle extends FieldHandle {\\n /** Открыть popover с деревом. */\\n open(): void;\\n /** Закрыть popover (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить весь выбор. */\\n clear(): void;\\n /** Перечитать уровень дерева. Действует, только пока popover открыт. */\\n refresh(id?: string | null): Promise<void>;\\n}","summary":"Императивный handle {@link ComboboxTreeMulti}: baseline {@link FieldHandle} на кнопке-триггере + управление popover\'ом и уровнями дерева.","description":"Императивный handle {@link ComboboxTreeMulti}: baseline {@link FieldHandle} на кнопке-триггере\\n+ управление popover\'ом и уровнями дерева.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTreeMultiProps","kind":"interface","signature":"export interface ComboboxTreeMultiProps {\\n className?: string;\\n /**\\n * Выбранные узлы (`node.id`). Приходит массивом всегда: `multiValueAdapter` разворачивает\\n * `null` в `[]`, потому что рендер ходит по значению `.includes`/`.map`.\\n */\\n value?: string[];\\n /** Изменение выбора. Всегда получает НОВЫЙ массив — см. `multiValueAdapter`. */\\n onChange?: (value: string[]) => void;\\n /** Срабатывает при закрытии popover (снятие фокуса). */\\n onBlur?: () => void;\\n /** Узлы верхнего уровня. Не задан вместе с `loadChildren`. */\\n nodes?: readonly TreeNode[];\\n /** Ленивое чтение уровня при первом раскрытии ветки; `null` — верхний уровень. */\\n loadChildren?: (node: TreeNode | null) => Promise<readonly TreeNode[]>;\\n /** Ветки, раскрытые при открытии списка. Пути до выбранных узлов раскрываются и без него. */\\n defaultExpandedIds?: readonly string[];\\n /**\\n * Что можно выбрать. По умолчанию `\'leaf\'` — выбор файлов: щелчок по каталогу его раскрывает.\\n */\\n selectable?: TreeSelectable;\\n /** Подсказка в триггере, пока ничего не выбрано. По умолчанию `\'Выберите файлы...\'`. */\\n placeholder?: string;\\n /** Подсказка в поле поиска. По умолчанию `\'Поиск...\'`. */\\n searchPlaceholder?: string;\\n /** Текст пустого состояния. По умолчанию `\'Ничего не найдено\'`. */\\n emptyText?: string;\\n /** Показывать крестик сброса ВСЕГО выбора справа от триггера. */\\n clearable?: boolean;\\n /**\\n * Потолок числа выбранных: по достижении невыбранные строки гаснут.\\n * Подсказка интерфейса, а НЕ правило формы — ограничение задавайте валидатором `maxLength(n)`.\\n */\\n maxItems?: number;\\n /** Сколько чипов показать в триггере до схлопывания в сводку. По умолчанию 3. */\\n summaryThreshold?: number;\\n /** Сколько строк дерева показать до появления прокрутки. По умолчанию 12. */\\n maxRows?: number;\\n disabled?: boolean;\\n /** id корневого элемента — по нему форма связывает подпись, описание и сообщение об ошибке. */\\n id?: string;\\n /**\\n * Префикс `data-testid`. Части поля адресуются им же: сам он на триггере, `-search` на поле\\n * поиска, `-clear` на крестике, `-tree` на корне дерева и `-tree-<id узла>` на его строках.\\n * Триггер и дерево получают РАЗНЫЕ значения намеренно: одно и то же на двух элементах\\n * означало бы, что при открытом поповере селектор находит два узла вместо одного.\\n */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props компонента {@link ComboboxTreeMulti}.","description":"Props компонента {@link ComboboxTreeMulti}.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"comboboxTreeMultiPropsSchema","kind":"const","signature":"export const comboboxTreeMultiPropsSchema","summary":"Props-схема ComboboxTreeMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема ComboboxTreeMulti — единый источник `api.controls[]` (reformer-doc) и\\nDSL-валидации `componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'ComboboxTreeMulti\'` — отдельная запись каталога, а не проп `multiple`\\nу `ComboboxTree`: тип значения другой (`string[] | null` против `string | null`), а\\n`x-runtimeProps.value` у записи ровно один. Адаптер вшит в замыкание HOC на этапе вызова\\n`withFormControl` и переключаться на рендере не может.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree-multi/combobox-tree-multi.props.ts","entries":["./meta","./combobox"],"package":"@reformer/ui-kit"},{"name":"ComboboxTreeProps","kind":"interface","signature":"export interface ComboboxTreeProps {\\n className?: string;\\n /** Выбранный узел (`node.id`). `null` — ничего не выбрано. */\\n value?: string | null;\\n /** Обработчик выбора. При очистке приходит `null`. */\\n onChange?: (value: string | null) => void;\\n /** Срабатывает при закрытии popover (снятие фокуса). */\\n onBlur?: () => void;\\n /** Узлы верхнего уровня. Не задан вместе с `loadChildren`. */\\n nodes?: readonly TreeNode[];\\n /** Ленивое чтение уровня при первом раскрытии ветки; `null` — верхний уровень. */\\n loadChildren?: (node: TreeNode | null) => Promise<readonly TreeNode[]>;\\n /** Ветки, раскрытые при открытии списка. Путь до выбранного узла раскрывается и без него. */\\n defaultExpandedIds?: readonly string[];\\n /**\\n * Что можно выбрать. По умолчанию `\'leaf\'` — выбор файла: щелчок по каталогу его раскрывает.\\n * `\'all\'` разрешает выбрать и каталог.\\n */\\n selectable?: TreeSelectable;\\n /** Подсказка в триггере, пока ничего не выбрано. По умолчанию `\'Выберите файл...\'`. */\\n placeholder?: string;\\n /** Подсказка в поле поиска. По умолчанию `\'Поиск...\'`. */\\n searchPlaceholder?: string;\\n /** Текст пустого состояния. По умолчанию `\'Ничего не найдено\'`. */\\n emptyText?: string;\\n /** Показывать ли крестик очистки справа от значения. По умолчанию `false`. */\\n clearable?: boolean;\\n /** Сколько строк дерева показать до появления прокрутки. По умолчанию 12. */\\n maxRows?: number;\\n disabled?: boolean;\\n /** id корневого элемента — по нему форма связывает подпись, описание и сообщение об ошибке. */\\n id?: string;\\n /**\\n * Префикс `data-testid`. Части поля адресуются им же: сам он на триггере, `-search` на поле\\n * поиска, `-clear` на крестике, `-tree` на корне дерева и `-tree-<id узла>` на его строках.\\n * Триггер и дерево получают РАЗНЫЕ значения намеренно: одно и то же на двух элементах\\n * означало бы, что при открытом поповере селектор находит два узла вместо одного.\\n */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props компонента {@link ComboboxTree}.","description":"Props компонента {@link ComboboxTree}.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree/combobox-tree.tsx","entries":["./combobox"],"package":"@reformer/ui-kit"},{"name":"comboboxTreePropsSchema","kind":"const","signature":"export const comboboxTreePropsSchema","summary":"Props-схема ComboboxTree — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема ComboboxTree — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'ComboboxTree\'` — отдельная запись каталога, а не проп `tree` у `Combobox`:\\nсписок опций и дерево — разные структуры данных (`options` против `nodes`), а `x-runtimeProps`\\nзаписи описывают ровно один контракт значения. Прецедент — `ComboboxMulti` и `FileUploadAvatar`.","params":[],"examplesCount":0,"sourcePath":"src/components/combobox/variants/tree/combobox-tree.props.ts","entries":["./meta","./combobox"],"package":"@reformer/ui-kit"},{"name":"Command","kind":"function","signature":"function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>)","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit","usage":1},{"name":"commandBasePropsSchema","kind":"const","signature":"export const commandBasePropsSchema","summary":"Props-схема Command (cmdk CommandPrimitive) — корень командного меню, рендерит DOM-обёртку (div) и пробрасывает className.","description":"Props-схема Command (cmdk CommandPrimitive) — корень командного меню, рендерит DOM-обёртку\\n(div) и пробрасывает className. Управляемое состояние (value/defaultValue/onValueChange) и\\nкастомный filter — runtime, не в схеме. В схеме только статические булевы-переключатели поведения.","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"CommandDialog","kind":"function","signature":"function CommandDialog({\\n title = \'Command Palette\',\\n description = \'Search for a command to run...\',\\n children,\\n className,\\n showCloseButton = true,\\n ...props\\n}: React.ComponentProps<typeof Dialog> & {\\n title?: string;\\n description?: string;\\n className?: string;\\n showCloseButton?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandEmpty","kind":"function","signature":"function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandGroup","kind":"function","signature":"function CommandGroup({\\n className,\\n ...props\\n}: React.ComponentProps<typeof CommandPrimitive.Group>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandInput","kind":"function","signature":"function CommandInput({\\n className,\\n ...props\\n}: React.ComponentProps<typeof CommandPrimitive.Input>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandItem","kind":"function","signature":"function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandList","kind":"function","signature":"function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandSeparator","kind":"function","signature":"function CommandSeparator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof CommandPrimitive.Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"CommandShortcut","kind":"function","signature":"function CommandShortcut({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/command/variants/base/command-base.tsx","entries":["./command"],"package":"@reformer/ui-kit"},{"name":"ContextMenu","kind":"function","signature":"function ContextMenu({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"contextMenuBasePropsSchema","kind":"const","signature":"export const contextMenuBasePropsSchema","summary":"Props-схема ContextMenu (Radix ContextMenu.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/размеры — на ContextMenuContent).","description":"Props-схема ContextMenu (Radix ContextMenu.Root) — контекст-провайдер без DOM, поэтому НЕ несёт\\nclassName (стили/размеры — на ContextMenuContent). Открытие по правому клику: управляемого open нет,\\nonOpenChange — runtime-колбэк, в схему не входит. Статически задаём dir и modal.","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ContextMenuCheckboxItem","kind":"function","signature":"function ContextMenuCheckboxItem({\\n className,\\n children,\\n checked,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuContent","kind":"function","signature":"function ContextMenuContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuGroup","kind":"function","signature":"function ContextMenuGroup({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Group>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuItem","kind":"function","signature":"function ContextMenuItem({\\n className,\\n inset,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\\n inset?: boolean;\\n variant?: \'default\' | \'destructive\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuLabel","kind":"function","signature":"function ContextMenuLabel({\\n className,\\n inset,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuPortal","kind":"function","signature":"function ContextMenuPortal({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuRadioGroup","kind":"function","signature":"function ContextMenuRadioGroup({\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuRadioItem","kind":"function","signature":"function ContextMenuRadioItem({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuSeparator","kind":"function","signature":"function ContextMenuSeparator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuShortcut","kind":"function","signature":"function ContextMenuShortcut({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuSub","kind":"function","signature":"function ContextMenuSub({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuSubContent","kind":"function","signature":"function ContextMenuSubContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuSubTrigger","kind":"function","signature":"function ContextMenuSubTrigger({\\n className,\\n inset,\\n children,\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"ContextMenuTrigger","kind":"function","signature":"function ContextMenuTrigger({\\n ...props\\n}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/context-menu/variants/base/context-menu-base.tsx","entries":[".","./context-menu"],"package":"@reformer/ui-kit"},{"name":"DataGrid","kind":"function","signature":"export function DataGrid<Row>({ settings, className }: DataGridProps<Row>): React.ReactNode","summary":"Data-driven таблица поверх презентационного {@link Table}.","description":"Data-driven таблица поверх презентационного {@link Table}. Держит состояние\\nпагинации / сортировки / фильтров, получает строки из `settings.dataProvider`\\n(server-driven, `manual*` у","params":[],"example":"Server-driven список с сортировкой и пагинацией\\n```tsx\\nimport { DataGrid, type TableSettings } from \'@reformer/ui-kit/table\';\\n\\nconst settings: TableSettings<User> = {\\ncolumns: [\\n{ id: \'name\', header: \'Имя\', accessor: (u) => u.name, sortable: true },\\n{ id: \'email\', header: \'E-mail\', accessor: (u) => u.email },\\n],\\npageSize: 20,\\nrowKey: (u) => u.id,\\ndataProvider: async ({ pagination, sorting }) => {\\nconst res = await fetch(`/api/users?page=${pagination.pageIndex}&sort=${sorting[0]?.id ?? \'\'}`);\\nconst { rows, total } = await res.json();\\nreturn { rows, total };\\n},\\n};\\n\\n<DataGrid settings={settings} />\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"DataGridProps","kind":"interface","signature":"export interface DataGridProps<Row> {\\n /** Настройки грида (data-provider, колонки, пагинация, выделение). */\\n settings: TableSettings<Row>;\\n /** Доп. className контейнера. */\\n className?: string;\\n}","summary":"Props {@link DataGrid}.","description":"Props {@link DataGrid}.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"dateAdapter","kind":"const","signature":"export const dateAdapter: FieldAdapter","summary":"Calendar / Date Picker — `selected` + `onSelect(Date | undefined)`.","description":"Calendar / Date Picker — `selected` + `onSelect(Date | undefined)`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"DatePicker","kind":"const","signature":"const DatePicker","summary":"DatePicker — Popover c Calendar (single) и кнопкой-триггером, показывающей выбранную дату.","description":"DatePicker — Popover c Calendar (single) и кнопкой-триггером, показывающей выбранную дату.\\nУправляемый контракт `value: Date | undefined` / `onChange(date)`. Поповер закрывается сам\\nпри выборе даты. Стандартное standalone-использование:\\n`<DatePicker value={date} onChange={setDate} />`.","params":[],"examplesCount":0,"topics":["overview","imperative-handles"],"sourcePath":"src/components/date-picker/variants/base/date-picker-base.tsx","entries":["./date-picker"],"package":"@reformer/ui-kit"},{"name":"DatePickerBaseField","kind":"const","signature":"export const DatePickerBaseField","summary":"Field-версия DatePicker: single-date со связкой `value: Date | null` + `onChange(Date | null)`.","description":"Field-версия DatePicker: single-date со связкой `value: Date | null` + `onChange(Date | null)`.\\n{@link dateAdapter} сводит `selected`/`onSelect` к value-based контракту формы; HOC отбрасывает\\n`control` (renderer-путь).\\n\\n`exposesHandle: true` — DatePicker сам реализует {@link DatePickerHandle}, ref форвардится\\nчерез мост прямо в него (passthrough).","params":[],"examplesCount":0,"sourcePath":"src/components/date-picker/variants/base/date-picker-base.field.tsx","entries":["./date-picker"],"package":"@reformer/ui-kit"},{"name":"datePickerBasePropsSchema","kind":"const","signature":"export const datePickerBasePropsSchema","summary":"Props-схема DatePicker (field-версия single-date) — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема DatePicker (field-версия single-date) — единый источник `api.controls[]` (reformer-doc)\\nи DSL-валидации `componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`value`/`onChange` — seam (маппятся адаптером на `selected`/`onSelect` Calendar), поэтому в\\n`x-runtimeProps`, а не в `properties`. `x-registryName: \'DatePicker\'` — на этот вариант смотрит\\nалиас `DatePickerField`.","params":[],"examplesCount":0,"sourcePath":"src/components/date-picker/variants/base/date-picker-base.props.ts","entries":["./meta","./date-picker"],"package":"@reformer/ui-kit"},{"name":"DatePickerField","kind":"const","signature":"export const DatePickerBaseField","summary":"Field-версия DatePicker: single-date со связкой `value: Date | null` + `onChange(Date | null)`.","description":"Field-версия DatePicker: single-date со связкой `value: Date | null` + `onChange(Date | null)`.\\n{@link dateAdapter} сводит `selected`/`onSelect` к value-based контракту формы; HOC отбрасывает\\n`control` (renderer-путь).\\n\\n`exposesHandle: true` — DatePicker сам реализует {@link DatePickerHandle}, ref форвардится\\nчерез мост прямо в него (passthrough).","params":[],"examplesCount":0,"topics":["overview","imperative-handles"],"sourcePath":"src/components/date-picker/variants/base/date-picker-base.field.tsx","entries":["./date-picker"],"package":"@reformer/ui-kit"},{"name":"DatePickerHandle","kind":"interface","signature":"export interface DatePickerHandle extends FieldHandle {\\n /** Открыть поповер с календарём. */\\n open(): void;\\n /** Закрыть поповер. */\\n close(): void;\\n}","summary":"Императивный handle {@link DatePicker}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/ getElement на кнопке-триггере) + управление поповером календаря.","description":"Императивный handle {@link DatePicker}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/\\ngetElement на кнопке-триггере) + управление поповером календаря. Достаётся из схемы:\\n`schema.node(\'customDate\').getRef<DatePickerHandle>().current?.open()`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/date-picker/variants/base/date-picker-base.tsx","entries":["./date-picker"],"package":"@reformer/ui-kit"},{"name":"DatePickerProps","kind":"interface","signature":"export interface DatePickerProps extends Omit<\\n React.ComponentProps<typeof Button>,\\n \'value\' | \'onChange\'\\n> {\\n /** Выбранная дата (управляемое значение). `undefined` — ничего не выбрано. */\\n value?: Date;\\n /** Колбэк выбора даты в календаре. Повторный клик по выбранной дате сбрасывает в `undefined`. */\\n onChange?: (date: Date | undefined) => void;\\n /** Текст кнопки-триггера, когда дата не выбрана. */\\n placeholder?: string;\\n /** Формат отображения выбранной даты — токены `date-fns` (по умолчанию `PPP`). */\\n dateFormat?: string;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/date-picker/variants/base/date-picker-base.tsx","entries":["./date-picker"],"package":"@reformer/ui-kit"},{"name":"defaultPropSchemas","kind":"const","signature":"export const defaultPropSchemas: Record<string, PropsSchema>","summary":"Карта регистр-имя → полная props-схема дефолтного варианта (для renderer-json/MCP).","description":"Карта регистр-имя → полная props-схема дефолтного варианта (для renderer-json/MCP).","params":[],"examplesCount":0,"sourcePath":"src/meta.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"Dialog","kind":"function","signature":"function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"dialogBasePropsSchema","kind":"const","signature":"export const dialogBasePropsSchema","summary":"Props-схема Dialog (Radix Dialog.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/размеры — на DialogContent).","description":"Props-схема Dialog (Radix Dialog.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className\\n(стили/размеры — на DialogContent). Управляемое состояние (open/onOpenChange) — runtime, не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"DialogClose","kind":"function","signature":"function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogContent","kind":"function","signature":"function DialogContent({\\n className,\\n children,\\n showCloseButton = true,\\n ...props\\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\\n showCloseButton?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogDescription","kind":"function","signature":"function DialogDescription({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DialogPrimitive.Description>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogFooter","kind":"function","signature":"function DialogFooter({\\n className,\\n showCloseButton = false,\\n children,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n showCloseButton?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogHeader","kind":"function","signature":"function DialogHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogOverlay","kind":"function","signature":"function DialogOverlay({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogPortal","kind":"function","signature":"function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogTitle","kind":"function","signature":"function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DialogTrigger","kind":"function","signature":"function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dialog/variants/base/dialog-base.tsx","entries":[".","./dialog"],"package":"@reformer/ui-kit"},{"name":"DirectionProvider","kind":"function","signature":"function DirectionProvider({\\n dir,\\n direction,\\n children,\\n}: React.ComponentProps<typeof Direction.DirectionProvider> & {\\n direction?: React.ComponentProps<typeof Direction.DirectionProvider>[\'dir\'];\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/direction/variants/base/direction-base.tsx","entries":[".","./direction"],"package":"@reformer/ui-kit"},{"name":"Drawer","kind":"function","signature":"function Drawer({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"drawerBasePropsSchema","kind":"const","signature":"export const drawerBasePropsSchema","summary":"Props-схема Drawer (vaul Drawer.Root) — контекст-провайдер без DOM (className/стили — на DrawerContent).","description":"Props-схема Drawer (vaul Drawer.Root) — контекст-провайдер без DOM (className/стили — на DrawerContent).\\nОставлены практичные конфиг-пропсы; низкоуровневые vaul-флаги (scrollLock/bodyStyles/…) не выносим.","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"DrawerClose","kind":"function","signature":"function DrawerClose({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Close>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerContent","kind":"function","signature":"function DrawerContent({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof DrawerPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerDescription","kind":"function","signature":"function DrawerDescription({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DrawerPrimitive.Description>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerFooter","kind":"function","signature":"function DrawerFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerHeader","kind":"function","signature":"function DrawerHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerOverlay","kind":"function","signature":"function DrawerOverlay({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerPortal","kind":"function","signature":"function DrawerPortal({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerTitle","kind":"function","signature":"function DrawerTitle({ className, ...props }: React.ComponentProps<typeof DrawerPrimitive.Title>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DrawerTrigger","kind":"function","signature":"function DrawerTrigger({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/drawer/variants/base/drawer-base.tsx","entries":["./drawer"],"package":"@reformer/ui-kit"},{"name":"DropdownMenu","kind":"function","signature":"function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"dropdownMenuBasePropsSchema","kind":"const","signature":"export const dropdownMenuBasePropsSchema","summary":"Props-схема DropdownMenu (Radix DropdownMenu.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/размеры — на DropdownMenuContent).","description":"Props-схема DropdownMenu (Radix DropdownMenu.Root) — контекст-провайдер без DOM, поэтому НЕ несёт\\nclassName (стили/размеры — на DropdownMenuContent). Управляемое состояние (open/onOpenChange) — runtime, не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuCheckboxItem","kind":"function","signature":"function DropdownMenuCheckboxItem({\\n className,\\n children,\\n checked,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuContent","kind":"function","signature":"function DropdownMenuContent({\\n className,\\n sideOffset = 4,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuGroup","kind":"function","signature":"function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuItem","kind":"function","signature":"function DropdownMenuItem({\\n className,\\n inset,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\\n inset?: boolean;\\n variant?: \'default\' | \'destructive\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuLabel","kind":"function","signature":"function DropdownMenuLabel({\\n className,\\n inset,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuPortal","kind":"function","signature":"function DropdownMenuPortal({\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuRadioGroup","kind":"function","signature":"function DropdownMenuRadioGroup({\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuRadioItem","kind":"function","signature":"function DropdownMenuRadioItem({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuSeparator","kind":"function","signature":"function DropdownMenuSeparator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuShortcut","kind":"function","signature":"function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuSub","kind":"function","signature":"function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuSubContent","kind":"function","signature":"function DropdownMenuSubContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuSubTrigger","kind":"function","signature":"function DropdownMenuSubTrigger({\\n className,\\n inset,\\n children,\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"DropdownMenuTrigger","kind":"function","signature":"function DropdownMenuTrigger({\\n ...props\\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/dropdown-menu/variants/base/dropdown-menu-base.tsx","entries":[".","./dropdown-menu"],"package":"@reformer/ui-kit"},{"name":"Empty","kind":"function","signature":"function Empty({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["overview","troubleshooting"],"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"emptyBasePropsSchema","kind":"const","signature":"export const emptyBasePropsSchema","summary":"Props-схема Empty — презентационный контейнер пустого состояния (обычный <div>, React.ComponentProps<\'div\'>).","description":"Props-схема Empty — презентационный контейнер пустого состояния (обычный <div>, React.ComponentProps<\'div\'>).\\nСвоих сериализуемых пропсов у Root нет; variant живёт на суб-компоненте EmptyMedia, не на корне —\\nпоэтому в схеме только className, который Root реально пробрасывает в DOM.","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"EmptyContent","kind":"function","signature":"function EmptyContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"EmptyDescription","kind":"function","signature":"function EmptyDescription({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"EmptyHeader","kind":"function","signature":"function EmptyHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"EmptyMedia","kind":"function","signature":"function EmptyMedia({\\n className,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof emptyMediaVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"emptyMediaVariants","kind":"const","signature":"const emptyMediaVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"EmptyTitle","kind":"function","signature":"function EmptyTitle({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/empty/variants/base/empty-base.tsx","entries":[".","./empty"],"package":"@reformer/ui-kit"},{"name":"ExampleCard","kind":"function","signature":"export function ExampleCard({\\n title,\\n description,\\n children,\\n code,\\n className,\\n bgColor = \'bg-card\',\\n}: ExampleCardProps)","summary":"Карточка-обёртка для демонстрации компонентов в playground: заголовок, описание, область с примером и кнопка переключения исходного кода с copy-to-clipboard.","description":"Карточка-обёртка для демонстрации компонентов в playground: заголовок,\\nописание, область с примером и кнопка переключения исходного кода с\\ncopy-to-clipboard.\\n\\nУтилита для playground/документации, не для продакшена.","params":[],"example":"Базовое использование\\n```tsx\\nimport { ExampleCard, Input } from \'@reformer/ui-kit\';\\nimport { useState } from \'react\';\\n\\nfunction Demo() {\\nconst [v, setV] = useState<string | null>(null);\\nreturn (\\n<ExampleCard\\ntitle=\\"Input — базовый\\"\\ndescription=\\"Однострочное поле с placeholder\\"\\ncode={`<Input value={v} onChange={setV} placeholder=\\"Email\\" />`}\\n>\\n<Input value={v} onChange={setV} placeholder=\\"Email\\" />\\n</ExampleCard>\\n);\\n}\\n```","examplesCount":2,"topics":["overview","layout-and-buttons","troubleshooting"],"sourcePath":"src/components/example-card/variants/base/example-card-base.tsx","entries":[".","./example-card"],"package":"@reformer/ui-kit","usage":85},{"name":"ExampleCardProps","kind":"interface","signature":"export interface ExampleCardProps {\\n /** Заголовок карточки (обязательный). */\\n title: string;\\n /** Описание под заголовком. */\\n description?: string;\\n /** Контент примера, отображаемый в режиме «пример». */\\n children: React.ReactNode;\\n /** Текст исходного кода, копируемый в clipboard в режиме «код». */\\n code: string;\\n /** Дополнительный CSS-класс контейнера. */\\n className?: string;\\n /** Tailwind-класс фона карточки. По умолчанию `\'bg-card\'` (адаптируется к теме). */\\n bgColor?: string;\\n}","summary":"Props компонента {@link ExampleCard}.","description":"Props компонента {@link ExampleCard}.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/example-card/variants/base/example-card-base.tsx","entries":[".","./example-card"],"package":"@reformer/ui-kit"},{"name":"Field","kind":"function","signature":"function Field({\\n className,\\n orientation = \'vertical\',\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof fieldVariants>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields","form-array-section","imperative-handles","form-layout"],"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldAdapter","kind":"interface","signature":"export interface FieldAdapter {\\n /** Проп, из которого примитив читает значение: `\'value\'` | `\'checked\'` | `\'pressed\'` | `\'selected\'`. */\\n valueProp: string;\\n /** Колбэк, через который примитив эмитит: `\'onChange\'` | `\'onCheckedChange\'` | `\'onValueChange\'` | … */\\n changeProp: string;\\n /** emit примитива → значение поля (`e.target.value`, `checked` bool, `number[]`→number, …). */\\n fromEmit: (arg: unknown, rest: Record<string, unknown>) => unknown;\\n /** значение поля → `valueProp` примитива (+ coerce `null`/`undefined`). */\\n toValue: (value: unknown) => unknown;\\n /**\\n * Проброс blur. По умолчанию `onBlur` пробрасывается как есть. Некоторым контролам нужен\\n * другой канал (напр. Select мапит blur на `onOpenChange(false)`).\\n */\\n bindBlur?: (onBlur: (() => void) | undefined) => Record<string, unknown>;\\n /** Доп. ключи убрать перед спредом в примитив (помимо всегда снимаемых `control`/`value`/`onChange`/`onBlur`). */\\n strip?: string[];\\n}","summary":"Адаптер поля: описывает, как разный event-shape shadcn-примитива (`value`/`onChange`, `checked`/`onCheckedChange`, `value`/`onValueChange`, …) сводится к value-based контракту ReFormer-формы — `value` + `onChange(value)` + `onBlur`.","description":"Адаптер поля: описывает, как разный event-shape shadcn-примитива\\n(`value`/`onChange`, `checked`/`onCheckedChange`, `value`/`onValueChange`, …)\\nсводится к value-based контракту ReFormer-формы — `value` + `onChange(value)` + `onBlur`.\\n\\nОдин адаптер = один event-shape. Экзотический контроль, не выразимый через эти поля,\\n— стоп-условие playbook (эскалация к оркестратору), а не «ещё один хак в HOC».","params":[],"examplesCount":0,"topics":["text-fields","form-field-integration","imperative-handles"],"sourcePath":"src/fields/with-form-control.tsx","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"FieldContent","kind":"function","signature":"function FieldContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["form-layout"],"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldDescription","kind":"function","signature":"function FieldDescription({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldError","kind":"function","signature":"function FieldError({\\n className,\\n children,\\n errors,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n errors?: Array<{ message?: string } | undefined>;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldGroup","kind":"function","signature":"function FieldGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldHandle","kind":"interface","signature":"export interface FieldHandle {\\n /** Сфокусировать поле (делегирует на DOM-элемент примитива). */\\n focus(): void;\\n /** Снять фокус. */\\n blur(): void;\\n /** Проскроллить поле в область видимости. */\\n scrollIntoView(opts?: ScrollIntoViewOptions): void;\\n /** Живой DOM-элемент поля (или `null` до монтирования / для размонтированной ноды). */\\n getElement(): HTMLElement | null;\\n}","summary":"Базовый императивный контракт любого field-компонента ReFormer.","description":"Базовый императивный контракт любого field-компонента ReFormer.\\n\\nСинтезируется HOC {@link withFormControl} из DOM-узла примитива. Rich-handle композитов\\n(SelectAsync, DatePicker, Combobox, InputPassword) расширяют его своими методами\\n(`open`/`close`/`reload`/`toggleVisibility`/…).\\n\\nДостаётся из render-схемы по селектору:\\n`schema.node(sel).getRef<FieldHandle>().current?.focus()`.\\n\\nПокрывает ТОЛЬКО истинно императивные действия. Реактивное состояние\\n(value / disabled / visible / options / validation) остаётся в слое behaviors —\\nчерез handle его НЕ дублируют. См. docs/plans/useimperativehandle-refactored-blossom.md.","params":[],"examplesCount":0,"topics":["layout-and-buttons","imperative-handles"],"sourcePath":"src/fields/field-handle.ts","entries":[".","./fields"],"package":"@reformer/ui-kit","usage":4},{"name":"FieldLabel","kind":"function","signature":"function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldLegend","kind":"function","signature":"function FieldLegend({\\n className,\\n variant = \'legend\',\\n ...props\\n}: React.ComponentProps<\'legend\'> & { variant?: \'legend\' | \'label\' })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldSeparator","kind":"function","signature":"function FieldSeparator({\\n children,\\n className,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n children?: React.ReactNode;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldSet","kind":"function","signature":"function FieldSet({ className, ...props }: React.ComponentProps<\'fieldset\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"FieldTitle","kind":"function","signature":"function FieldTitle({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/field/variants/base/field-base.tsx","entries":[".","./field"],"package":"@reformer/ui-kit"},{"name":"fieldWrapperPropsSchema","kind":"const","signature":"export const fieldWrapperPropsSchema: PropsSchema","summary":"Контракт враппера `FormField`: props, которые вынимает CDK-обёртка (не примитив).","description":"Контракт враппера `FormField`: props, которые вынимает CDK-обёртка (не примитив).\\nПодмешивается в каждую field-схему через `mergeFieldPropsSchema`.\\n\\n`label`/`required` — живые (рисуются `FormField.Label`: `FormFieldRoot.tsx:80` → `FormFieldLabel.tsx:51`).\\n`testId` — meta-проп: уходит в `data-testid`, в примитив/DOM как проп не течёт.\\n`description` — под shadcn `Field` (`FieldDescription`); FormField перестроен на нём в волне 0.","params":[],"examplesCount":0,"sourcePath":"src/components/form-field/form-field.props.ts","entries":[".","./form-field"],"package":"@reformer/ui-kit"},{"name":"fileUploadAdapter","kind":"const","signature":"export const fileUploadAdapter: FieldAdapter","summary":"FileUpload уже value-based (`value: File[] | RemoteFileRef[] | null`, `onChange(value)`, `onBlur`) — адаптер почти identity: маппинга DOM-события нет, HOC нужен лишь чтобы отбросить `control` (renderer-путь).","description":"FileUpload уже value-based (`value: File[] | RemoteFileRef[] | null`, `onChange(value)`,\\n`onBlur`) — адаптер почти identity: маппинга DOM-события нет, HOC нужен лишь чтобы\\nотбросить `control` (renderer-путь). Пустой массив нормализуется в `null`,\\nчтобы `required()` срабатывал без изменений.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadAvatar","kind":"function","signature":"export function FileUploadAvatar({\\n ref,\\n shape = \'circle\',\\n ...props\\n}: FileUploadAvatarProps & Record<string, unknown> & { ref?: React.Ref<FileUploadFieldHandle> })","summary":"FileUpload (вариант `avatar`) — одиночное изображение с превью: круглая/квадратная кликабельная зона (клик/drop/Enter — выбрать или заменить), оверлеи прогресса и ошибки, кнопка удаления.","description":"FileUpload (вариант `avatar`) — одиночное изображение с превью: круглая/квадратная\\nкликабельная зона (клик/drop/Enter — выбрать или заменить), оверлеи прогресса и\\nошибки, кнопка удаления. `accept` по умолчанию `image/*`, файл всегда один\\n(новый выбор заменяет текущий).","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/file-upload/variants/avatar/file-upload-avatar.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit","usage":3},{"name":"FileUploadAvatarField","kind":"const","signature":"export const FileUploadAvatarField","summary":"Field-версия avatar-варианта.","description":"Field-версия avatar-варианта. Rich handle реализует сам композит.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/avatar/file-upload-avatar.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit","usage":3},{"name":"FileUploadAvatarProps","kind":"interface","signature":"export interface FileUploadAvatarProps extends Omit<\\n FileUploadBaseProps,\\n \'multiple\' | \'maxFiles\' | \'allowPaste\' | \'hint\' | \'placeholder\'\\n> {\\n /** Форма превью. @default \'circle\' */\\n shape?: \'circle\' | \'square\';\\n /** Доступное имя зоны (aria-label; текста у зоны нет). @default \'Загрузить изображение\' */\\n label?: string;\\n}","summary":"Props avatar-варианта: single-файл, только изображения по умолчанию.","description":"Props avatar-варианта: single-файл, только изображения по умолчанию.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/avatar/file-upload-avatar.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"fileUploadAvatarPropsSchema","kind":"const","signature":"export const fileUploadAvatarPropsSchema","summary":"Props-схема варианта `file-upload/avatar` — single-изображение с превью.","description":"Props-схема варианта `file-upload/avatar` — single-изображение с превью.\\nОтдельное registry-имя: другой тип значения (`File | RemoteFileRef | null`\\nвместо массива) — другой seam-контракт.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/avatar/file-upload-avatar.props.ts","entries":[".","./meta","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadBase","kind":"function","signature":"export function FileUploadBase({\\n ref,\\n ...props\\n}: FileUploadBaseProps & Record<string, unknown> & { ref?: React.Ref<FileUploadFieldHandle> })","summary":"FileUpload (вариант `button`) — компактное поле загрузки файлов: кнопка «Выбрать файлы» + список выбранных на презентационном `Attachment`.","description":"FileUpload (вариант `button`) — компактное поле загрузки файлов: кнопка «Выбрать\\nфайлы» + список выбранных на презентационном `Attachment`. Controlled по seam\\n(`value`/`onChange`/`onBlur`/`disabled`); поведение целиком в\\n`@reformer/cdk/file-upload`.\\n\\n`aria-*`/`id` из FormField ложатся на кнопку-триггер (rest-spread).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadBaseField","kind":"const","signature":"export const FileUploadBaseField","summary":"`exposesHandle: true` — FileUploadBase сам реализует {@link FileUploadFieldHandle} (useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — FileUploadBase сам реализует {@link FileUploadFieldHandle}\\n(useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит\\n(passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadBaseProps","kind":"interface","signature":"export interface FileUploadBaseProps extends Omit<UseFileUploadOptions, \'id\'> {\\n /**\\n * Подпись поля — конвенция FormField (`componentProps.label` рендерит обёртка).\\n * Сам компонент её НЕ отображает (иначе текст дублировался бы), только снимает из DOM-spread.\\n */\\n label?: string;\\n /** Видимый текст триггера/зоны. @default \'Выбрать файлы\' (button) */\\n placeholder?: string;\\n /** Подсказка под триггером (ограничения: типы, размер). */\\n hint?: string;\\n /**\\n * Явно пометить поле невалидным (стилизация рамки у dropzone/input/avatar).\\n * Под FormField не нужен: обёртка сама передаёт `aria-invalid` при ошибке валидации.\\n * Вариант button внешний вид не меняет — ошибку показывает FormField.Error.\\n */\\n invalid?: boolean;\\n /** Доп. CSS-класс контейнера. */\\n className?: string;\\n id?: string;\\n}","summary":"Общие props вариантов FileUpload: опции CDK-хука + презентационные.","description":"Общие props вариантов FileUpload: опции CDK-хука + презентационные.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"fileUploadBasePropsSchema","kind":"const","signature":"export const fileUploadBasePropsSchema","summary":"Props-схема варианта `file-upload/base` — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема варианта `file-upload/base` — единый источник `api.controls[]`\\n(reformer-doc) и DSL-валидации `componentProps` (renderer-json).\\n\\n`x-registryName: \'FileUpload\'` — на это имя смотрит диспетчер `FileUploadField`\\n(варианты `button`/`dropzone` — один контракт, разный визуал).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.props.ts","entries":[".","./meta","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadDropzone","kind":"function","signature":"export function FileUploadDropzone({\\n ref,\\n ...props\\n}: FileUploadDropzoneProps & Record<string, unknown> & { ref?: React.Ref<FileUploadFieldHandle> })","summary":"FileUpload (вариант `dropzone`) — зона drag-and-drop: рамка с подсветкой состояния (`data-dragging` из CDK), клик и Enter/Space открывают пикер (drop — не единственный канал).","description":"FileUpload (вариант `dropzone`) — зона drag-and-drop: рамка с подсветкой состояния\\n(`data-dragging` из CDK), клик и Enter/Space открывают пикер (drop — не единственный\\nканал). Список файлов — тот же `FileUploadItemList`, что в варианте `button`.\\n\\n`aria-*`/`id` из FormField ложатся на зону (rest-spread).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/dropzone/file-upload-dropzone.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit","usage":3},{"name":"FileUploadDropzoneField","kind":"const","signature":"export const FileUploadDropzoneField","summary":"Field-версия dropzone-варианта: тот же value-based адаптер, что у base (контракт один — визуал разный).","description":"Field-версия dropzone-варианта: тот же value-based адаптер, что у base\\n(контракт один — визуал разный). Rich handle реализует сам композит.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/dropzone/file-upload-dropzone.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadDropzoneProps","kind":"type","signature":"export type FileUploadDropzoneProps = FileUploadBaseProps;","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/dropzone/file-upload-dropzone.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadField","kind":"const","signature":"export const FileUploadField","summary":"Field-версия FileUpload — диспетчер по `variant`: `dropzone` → зона drag-and-drop, `input` → компактный инпут с кнопкой-иконкой, иначе кнопка-триггер (base).","description":"Field-версия FileUpload — диспетчер по `variant`: `dropzone` → зона drag-and-drop,\\n`input` → компактный инпут с кнопкой-иконкой, иначе кнопка-триггер (base).\\nКонтракт значения один (`File[] | RemoteFileRef[] | null`), различается только\\nпредставление — поэтому одно registry-имя `FileUpload`.\\n\\n`forwardRef`: все пути форвардят ref и отдают rich {@link FileUploadFieldHandle}\\n(собственный `useImperativeHandle` композитов, HOC — passthrough).\\n\\nSingle-изображение с превью — отдельный {@link FileUploadAvatarField}\\n(другой тип значения → другое registry-имя `FileUploadAvatar`).","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/file-upload-field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit","usage":15},{"name":"FileUploadFieldHandle","kind":"interface","signature":"export interface FileUploadFieldHandle extends FieldHandle {\\n /** Открыть системный пикер файлов. */\\n openFilePicker(): void;\\n /** Очистить список (активные загрузки прерываются). */\\n clear(): void;\\n /** Прервать все активные загрузки (элементы остаются с ошибкой `uploadAborted`). */\\n abort(): void;\\n}","summary":"Императивный handle field-версий FileUpload: baseline {@link FieldHandle} (focus/blur/scrollIntoView/getElement от интерактивного элемента) + управление пикером и списком.","description":"Императивный handle field-версий FileUpload: baseline {@link FieldHandle}\\n(focus/blur/scrollIntoView/getElement от интерактивного элемента) + управление\\nпикером и списком. Достаётся из render-схемы:\\n`schema.node(\'documents\').getRef<FileUploadFieldHandle>().current?.openFilePicker()`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadInput","kind":"function","signature":"export function FileUploadInput({\\n ref,\\n ...props\\n}: FileUploadInputProps & Record<string, unknown> & { ref?: React.Ref<FileUploadFieldHandle> })","summary":"FileUpload (вариант `input`) — поле в виде текстового инпута с кнопкой-иконкой (скрепка): клик по полю или иконке открывает пикер, drop на поле принимает файлы, выбранные имена показываются внутри строкой, крестик очищает выбор.","description":"FileUpload (вариант `input`) — поле в виде текстового инпута с кнопкой-иконкой\\n(скрепка): клик по полю или иконке открывает пикер, drop на поле принимает файлы,\\nвыбранные имена показываются внутри строкой, крестик очищает выбор. Списка-превью\\nнет — компактный вариант для форм, где вложения второстепенны.\\n\\n`aria-*`/`id` из FormField ложатся на зону; `invalid` (или aria-invalid от FormField)\\nподсвечивает рамку как у Input.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/input/file-upload-input.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit","usage":3},{"name":"FileUploadInputField","kind":"const","signature":"export const FileUploadInputField","summary":"Field-версия input-варианта: тот же value-based адаптер, что у base/dropzone (контракт значения один — визуал компактного инпута).","description":"Field-версия input-варианта: тот же value-based адаптер, что у base/dropzone\\n(контракт значения один — визуал компактного инпута). Rich handle реализует композит.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/input/file-upload-input.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadInputProps","kind":"type","signature":"export type FileUploadInputProps = FileUploadBaseProps;","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/input/file-upload-input.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FileUploadItemList","kind":"function","signature":"export function FileUploadItemList({ className }: { className?: string })","summary":"Список выбранных файлов + отклонения последнего отбора.","description":"Список выбранных файлов + отклонения последнего отбора. Общий кусок вариантов\\n`button` и `dropzone`: CDK-слоты (semantics, статусы, действия) + презентационный\\n`Attachment` (визуал). Рендерится ТОЛЬКО внутри `CdkFileUpload.Root`.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-item-list.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"fileUploadSingleAdapter","kind":"const","signature":"export const fileUploadSingleAdapter: FieldAdapter","summary":"Avatar — single-файл: значение поля `File | RemoteFileRef | null`, а CDK-слой работает с массивом.","description":"Avatar — single-файл: значение поля `File | RemoteFileRef | null`, а CDK-слой\\nработает с массивом. Адаптер конвертирует single ↔ массив длины 1.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/avatar/file-upload-avatar.field.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"FormArray","kind":"function","signature":"export function FormArray({\\n items = [],\\n onAdd,\\n onRemove,\\n onMove,\\n title,\\n itemLabel,\\n addButtonLabel = \'+ Добавить\',\\n removeButtonLabel = \'Удалить\',\\n emptyMessage,\\n emptyMessageHint,\\n reorderable = false,\\n showRemoveOnSingle = false,\\n className = \'space-y-3 mt-2\',\\n cardClassName = \'mb-4 p-4 bg-card text-card-foreground rounded border\',\\n}: FormArrayProps): ReactNode","summary":"","params":[],"examplesCount":0,"topics":["overview","form-field-integration","form-array-section","imperative-handles","form-layout"],"sourcePath":"src/components/form-array/variants/base/form-array.tsx","entries":[".","./form-array"],"package":"@reformer/ui-kit","usage":10},{"name":"FormArrayProps","kind":"interface","signature":"export interface FormArrayProps extends ArrayComponentProps {\\n /** Отрендеренные элементы массива (инъектится рендерером). */\\n items?: ArrayItemSlot[];\\n /** Добавить элемент (инъектится рендерером; значение резолвится из `initialValue` узла). */\\n onAdd?: () => void;\\n /** Удалить элемент по индексу (инъектится рендерером). */\\n onRemove?: (index: number) => void;\\n /** Переместить элемент (инъектится рендерером). Нужен при `reorderable`. */\\n onMove?: (from: number, to: number) => void;\\n /** Заголовок секции (h3). */\\n title?: string;\\n /** Метка элемента — префикс-строка или функция `(model, index) => string`. */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n itemLabel?: string | ((model: any, index: number) => string);\\n /** Текст кнопки добавления. По умолчанию `\'+ Добавить\'`. */\\n addButtonLabel?: string;\\n /** Текст кнопки удаления. По умолчанию `\'Удалить\'`. */\\n removeButtonLabel?: string;\\n /** Сообщение пустого состояния. */\\n emptyMessage?: string;\\n /** Подсказка под пустым состоянием. */\\n emptyMessageHint?: string;\\n /** Кнопки ↑/↓ перестановки. По умолчанию `false`. */\\n reorderable?: boolean;\\n /** Показывать «Удалить» когда остался один элемент. По умолчанию `false`. */\\n showRemoveOnSingle?: boolean;\\n /** Внешний className секции. */\\n className?: string;\\n /** Класс card-обёртки элемента. */\\n cardClassName?: string;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/variants/base/form-array.tsx","entries":[".","./form-array"],"package":"@reformer/ui-kit"},{"name":"FormArraySection","kind":"function","signature":"export function FormArraySection<T extends object>({\\n control,\\n itemComponent: ItemComponent,\\n title,\\n itemLabel,\\n addButtonLabel = \'+ Добавить\',\\n removeButtonLabel = \'Удалить\',\\n emptyMessage,\\n emptyMessageHint,\\n hasItems,\\n initialValue,\\n showRemoveOnSingle = false,\\n reorderable = false,\\n maxItems,\\n className = \'space-y-3 mt-2\',\\n cardClassName = \'mb-4 p-4 bg-card text-card-foreground rounded border\',\\n ...rest\\n}: FormArraySectionProps<T>): ReactNode","summary":"Готовая UI-секция для динамического массива форм — стилизованная обёртка поверх headless-compound `@reformer/cdk/form-array`.","description":"Готовая UI-секция для динамического массива форм — стилизованная обёртка поверх\\nheadless-compound `@reformer/cdk/form-array`. Рендерит заголовок, кнопку\\n«Добавить», карточку с меткой на каждый элемент (плюс опциональные кнопки\\nудаления и перестановки ↑/↓) и сообщение пустого состояния.\\n\\n`control` принимает `FormArrayProxy<T>` или уже-резолвленный\\n`ArrayNode<T>`/`ModelArrayNode<T>`. `itemComponent` — единственная форма\\nрендера элемента: `ComponentType<{ control: FormProxy<T> }>` (тот же контракт,\\nчто у шага {@link FormWizardStep}). Внутри `RenderNodeComponent` проп `form`\\nинъектится автоматически (маркер `__selfManagedChildren`).\\n\\nПроп `hasItems` удобен для toggle-чекбоксов («У меня есть имущество»): при\\n`false` секция скрывается целиком.\\n\\n**Не для renderer-json.** Там массив описывается array-нодой, а компонент получает от\\nрендерера seam `items`/`onAdd`/`onRemove`/`onMove` — под `$component(FormArray)` нужен\\n{@link FormArray}. Если зарегистрировать сюда `FormArraySection`, `control` не придёт\\nи секция вернёт `null` (в dev это теперь сопровождается предупреждением в консоли).","params":[],"example":"Массив «Имущество» под чекбоксом-переключателем\\n```tsx\\nimport { FormArraySection } from \'@reformer/ui-kit/form-array\';\\n\\nfunction AdditionalInfo({ control }: { control: FormProxy<CreditApplication> }) {\\nconst hasProperty = useFormControlValue(control.hasProperty) as boolean;\\nreturn (\\n<FormArraySection\\ntitle=\\"Имущество\\"\\ncontrol={control.properties}\\nitemComponent={PropertyForm}\\nitemLabel=\\"Имущество\\"\\naddButtonLabel=\\"+ Добавить имущество\\"\\nemptyMessage=\'Нажмите \\"Добавить имущество\\" для добавления информации\'\\nhasItems={hasProperty}\\ninitialValue={createBlankProperty()}\\nreorderable\\n/>\\n);\\n}\\n```","examplesCount":1,"topics":["form-array-section","form-layout"],"sourcePath":"src/components/form-array/variants/base/form-array-section.tsx","entries":[".","./form-array"],"package":"@reformer/ui-kit","usage":5},{"name":"FormArraySectionProps","kind":"interface","signature":"export interface FormArraySectionProps<T extends object> {\\n /** Уже-резолвленный ArrayNode/ModelArrayNode/FormArrayProxy. */\\n control: FormArrayProxy<T> | ArrayNode<T> | undefined;\\n\\n /** React FC получает `control: FormProxy<T>` для каждого элемента. */\\n itemComponent: ComponentType<{ control: FormProxy<T> }>;\\n\\n /** Заголовок секции (рендерится h3). */\\n title?: string;\\n\\n /** Метка для каждого item — строка-префикс или функция. */\\n itemLabel?: string | ((control: FormProxy<T>, index: number) => string);\\n\\n /** Текст кнопки добавления. По умолчанию `\'+ Добавить\'`. */\\n addButtonLabel?: string;\\n\\n /** Текст кнопки удаления. По умолчанию `\'Удалить\'`. */\\n removeButtonLabel?: string;\\n\\n /** Сообщение пустого состояния. */\\n emptyMessage?: string;\\n\\n /** Подсказка под пустым состоянием. */\\n emptyMessageHint?: string;\\n\\n /**\\n * Условие видимости секции. Если `false` — секция полностью скрыта.\\n * Удобно для toggle-чекбоксов вида «У меня есть имущество».\\n */\\n hasItems?: boolean;\\n\\n /**\\n * Plain-leaf значения для новых items (передаётся в `FormArray.AddButton`).\\n * НЕ FieldConfig — только примитивы по форме item-типа `T`.\\n *\\n * Тип `Partial<T>` — TS проверит, что initialValue совместим с типом элемента.\\n * Передавайте generic явно для лучшей type-safety:\\n * `<FormArraySection<PropertyItem> initialValue={createPropertyItem()} ...>`.\\n */\\n initialValue?: Partial<T>;\\n\\n /** Показывать «Удалить» когда остался один элемент. По умолчанию `false`. */\\n showRemoveOnSingle?: boolean;\\n\\n /**\\n * Показывать кнопки ↑/↓ для перестановки элементов. По умолчанию `false`\\n * (обратная совместимость — существующие массивы не меняются).\\n */\\n reorderable?: boolean;\\n\\n /** Максимум items — AddButton отключается при достижении. */\\n maxItems?: number;\\n\\n /** Внешний className секции. */\\n className?: string;\\n\\n /** Класс card-обёртки каждого item. */\\n cardClassName?: string;\\n\\n /**\\n * FormProxy. Авто-инъектится `RenderNodeComponent` через\\n * `__selfManagedChildren` маркер. Передавать вручную — только при\\n * использовании вне стандартного render-tree.\\n */\\n form?: FormProxy<unknown>;\\n\\n /**\\n * Field wrapper для дочерних полей. Авто-инъектится `RenderNodeComponent`;\\n * переопределить для использования другого wrapper в этой секции.\\n */\\n fieldWrapper?: ComponentType<FieldWrapperProps>;\\n}","summary":"Пропсы {@link FormArraySection}.","description":"Пропсы {@link FormArraySection}.","params":[],"examplesCount":0,"sourcePath":"src/components/form-array/variants/base/form-array-section.tsx","entries":[".","./form-array"],"package":"@reformer/ui-kit"},{"name":"FormField","kind":"const","signature":"export const FormField","summary":"Готовый wrapper поля на визуальной базе shadcn `Field`, поверх headless `@reformer/cdk/form-field`: `Label` → `Control` → `Error` (+ опц.","description":"Готовый wrapper поля на визуальной базе shadcn `Field`, поверх headless\\n`@reformer/cdk/form-field`: `Label` → `Control` → `Error` (+ опц. `Description`, pending).\\nПодключается `<FormField control={…} />` или как `fieldWrapper` для `FormRenderer`.\\n\\n- Для inline-контролов (Checkbox/Switch — `reformerLayout=\'inline-label\'`) верхняя подпись не рендерится.\\n- При `pending` (async-валидация) под полем показывается «Проверка…».\\n- `React.memo` по ссылке `control` — критично для больших форм.","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields","form-field-integration","troubleshooting","form-wizard","form-array-section","input-mask","form-layout"],"sourcePath":"src/components/form-field/form-field.tsx","entries":[".","./form-field"],"package":"@reformer/ui-kit","usage":156},{"name":"FormFieldProps","kind":"interface","signature":"export interface FormFieldProps {\\n /**\\n * Поле формы. Из него берутся `component` (тип контрола), `componentProps`, `value`, `error`,\\n * `pending`, `setValue`, `blur`. Контрол инстанцируется автоматически через `CdkFormField.Control`.\\n */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n control: FieldNode<any>;\\n /** Дополнительный CSS-класс корневого `Field`. */\\n className?: string;\\n /**\\n * Префикс `data-testid` (`field-<id>`, `label-<id>`, `input-<id>`, `error-<id>`).\\n * Если опущен — берётся `componentProps.testId`, иначе `\'unknown\'`.\\n */\\n testId?: string;\\n /**\\n * Кастомный input — оборачивается в `CdkFormField.Control asChild` (нестандартный контрол,\\n * не зарегистрированный в `control.component`).\\n */\\n children?: React.ReactNode;\\n}","summary":"Props компонента {@link FormField}.","description":"Props компонента {@link FormField}.","params":[],"examplesCount":0,"topics":["form-field-integration"],"sourcePath":"src/components/form-field/form-field.tsx","entries":[".","./form-field"],"package":"@reformer/ui-kit"},{"name":"FormWizard","kind":"const","signature":"const FormWizard","summary":"Готовая многошаговая форма (multi-step wizard) — стилизованная обёртка поверх headless-compound `@reformer/cdk/form-wizard`.","description":"Готовая многошаговая форма (multi-step wizard) — стилизованная обёртка поверх\\nheadless-compound `@reformer/cdk/form-wizard`. Собирает Indicator, тело шагов,\\nActions (Назад / Далее / Отправить) и Progress в единый layout, работает с\\nодной {@link FormProxy} и декларативным списком {@link FormWizardStep}.\\n\\nОдин компонент покрывает TS-flow, renderer-react и renderer-json за счёт\\nполиморфного {@link FormWizardStepBody}. Валидация по шагам и submit-валидация\\nзадаются через `config` (`{ validateStep, validateAll }`, обычно обёртки над\\n`validateModel` из `@reformer/core/validation`). Императивный доступ (submit/навигация снаружи дерева) —\\nчерез `ref` типа `FormWizardHandle<T>`.\\n\\nЭкспонирует compound-слоты `FormWizard.Indicator` / `.Step` / `.Actions` /\\n`.Progress` для кастомной раскладки.","params":[],"example":"Кредитная заявка с 3 шагами и внешним submit\\n```tsx\\nimport { useMemo, useRef } from \'react\';\\nimport { FormWizard, type FormWizardStep } from \'@reformer/ui-kit/form-wizard\';\\nimport type { FormWizardHandle } from \'@reformer/cdk/form-wizard\';\\n\\nconst STEPS: FormWizardStep<CreditApplication>[] = [\\n{ number: 1, title: \'Кредит\', icon: \'💰\', body: BasicInfoForm },\\n{ number: 2, title: \'Данные\', icon: \'👤\', body: PersonalInfoForm },\\n{ number: 3, title: \'Подтверждение\', icon: \'✓\', body: ConfirmationForm },\\n];\\n\\nfunction CreditForm() {\\nconst navRef = useRef<FormWizardHandle<CreditApplication>>(null);\\nconst { form, model } = useMemo(() => createCreditForm(), []);\\nconst config = useMemo(() => makeValidationConfig(model), [model]);\\n\\nconst onSubmit = () =>\\nnavRef.current?.submit((values) => api.submit(values));\\n\\nreturn (\\n<FormWizard\\nref={navRef}\\nform={form}\\nconfig={config}\\nsteps={STEPS}\\nonSubmit={onSubmit}\\n/>\\n);\\n}\\n```","examplesCount":1,"related":["FormWizardStep","StepIndicator","FormWizardActions","FormWizardProgress"],"topics":["overview","layout-and-buttons","form-wizard","imperative-handles"],"sourcePath":"src/components/form-wizard/variants/base/form-wizard.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit","usage":9},{"name":"FormWizardActions","kind":"const","signature":"export const FormWizardActions: FC<FormWizardActionsProps>","summary":"Кнопки навигации wizard\'а: «Назад» / «Далее →» / «Отправить».","description":"Кнопки навигации wizard\'а: «Назад» / «Далее →» / «Отправить». На первом шаге\\nскрывает «Назад», на последнем показывает «Отправить» вместо «Далее». Во время\\nвалидации/отправки показывает промежуточные подписи и блокирует кнопку.\\n\\nРендерится из headless-слота `<FormWizard.Actions>` через render-prop, поэтому\\n`prev`/`next`/`submit`/флаги приходят автоматически. Готовый {@link FormWizard}\\nуже подключает этот компонент — использовать напрямую нужно только для кастомной\\nраскладки.","params":[],"example":"Кастомные подписи в слоте Actions\\n```tsx\\n<FormWizard.Actions onSubmit={onSubmit}>\\n{(actions) => (\\n<FormWizardActions\\n{...actions}\\nsubmitLabel=\\"Оформить заявку\\"\\nclassName=\\"mt-8\\"\\n/>\\n)}\\n</FormWizard.Actions>\\n```","examplesCount":1,"sourcePath":"src/components/form-wizard/variants/base/form-wizard-actions.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"FormWizardActionsProps","kind":"interface","signature":"export interface FormWizardActionsProps extends FormWizardActionsRenderProps {\\n /** Внешний CSS-класс контейнера кнопок. */\\n className?: string;\\n /** Подпись кнопки «Назад». По умолчанию `\'← Назад\'`. */\\n prevLabel?: string;\\n /** Подпись кнопки «Далее». По умолчанию `\'Далее →\'`. */\\n nextLabel?: string;\\n /** Подпись кнопки отправки на последнем шаге. По умолчанию `\'Отправить заявку\'`. */\\n submitLabel?: string;\\n /** Подпись кнопки «Далее» во время валидации шага. По умолчанию `\'Проверка...\'`. */\\n validatingLabel?: string;\\n /** Подпись кнопки отправки во время submit. По умолчанию `\'Отправка...\'`. */\\n submittingLabel?: string;\\n}","summary":"Пропсы {@link FormWizardActions}: render-props навигации из headless-слота `<FormWizard.Actions>` (`prev`, `next`, `submit`, `isFirstStep`, `isLastStep`, `isValidating`, `isSubmitting`) плюс переопределяемые подписи кнопок.","description":"Пропсы {@link FormWizardActions}: render-props навигации из headless-слота\\n`<FormWizard.Actions>` (`prev`, `next`, `submit`, `isFirstStep`, `isLastStep`,\\n`isValidating`, `isSubmitting`) плюс переопределяемые подписи кнопок.\\n\\nВсе `*Label`-пропсы опциональны и имеют русские дефолты.","params":[],"examplesCount":0,"topics":["form-wizard"],"sourcePath":"src/components/form-wizard/variants/base/form-wizard-actions.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"FormWizardProgress","kind":"const","signature":"export const FormWizardProgress: FC<FormWizardProgressProps>","summary":"Текстовый индикатор прогресса wizard\'а — по умолчанию рендерит «Шаг N из M • X% завершено».","description":"Текстовый индикатор прогресса wizard\'а — по умолчанию рендерит\\n«Шаг N из M • X% завершено». Формат строки переопределяется пропом `format`.\\n\\nРендерится из headless-слота `<FormWizard.Progress>` через render-prop\\n(`current`/`total`/`percent` приходят автоматически). Готовый {@link FormWizard}\\nуже подключает этот компонент; напрямую нужен только для кастомной раскладки.","params":[],"example":"Свой формат строки прогресса\\n```tsx\\n<FormWizard.Progress>\\n{(progress) => (\\n<FormWizardProgress\\n{...progress}\\nformat={({ current, total }) => `${current} / ${total}`}\\n/>\\n)}\\n</FormWizard.Progress>\\n```","examplesCount":1,"sourcePath":"src/components/form-wizard/variants/base/form-wizard-progress.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"FormWizardProgressProps","kind":"interface","signature":"export interface FormWizardProgressProps extends FormWizardProgressRenderProps {\\n /** Внешний CSS-класс контейнера. */\\n className?: string;\\n /**\\n * Кастомный форматтер строки прогресса. Получает `{ current, total, percent }`.\\n * По умолчанию — `\'Шаг N из M • X% завершено\'`.\\n */\\n format?: (props: FormWizardProgressRenderProps) => ReactNode;\\n}","summary":"Пропсы {@link FormWizardProgress}: render-props прогресса из слота `<FormWizard.Progress>` (`current`, `total`, `percent`) плюс `className` и переопределяемый `format`.","description":"Пропсы {@link FormWizardProgress}: render-props прогресса из слота\\n`<FormWizard.Progress>` (`current`, `total`, `percent`) плюс `className` и\\nпереопределяемый `format`.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/variants/base/form-wizard-progress.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"FormWizardProps","kind":"interface","signature":"export interface FormWizardProps<\\n // Constraint синхронизирован с headless cdk (`Record<string, any>`) — это\\n // снимает блокер инференции generic\'а T в JSX, когда T содержит nullable-\\n // числа (`number | null`). Constraint используется только для bound, not\\n // for direct value access.\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n T extends Record<string, any>,\\n TBody = never,\\n> extends FormWizardHeadlessProps<T> {\\n /** Внешний CSS-класс корневого контейнера. */\\n className?: string;\\n /** Декларативный список шагов (см. {@link FormWizardStep}). Порядок = порядок навигации. */\\n steps: FormWizardStep<T, TBody>[];\\n /**\\n * Колбэк отправки формы на последнем шаге. Вызывается только после успешного\\n * `config.validateAll`; при провале не вызывается, а поля помечаются `touched`,\\n * чтобы ошибки стали видны. Без `config.validateAll` отправка не блокируется.\\n */\\n onSubmit: HeadlessFormWizardActionsProps[\'onSubmit\'];\\n /**\\n * Стратегия отрисовки нестандартного `body`. Сам ui-kit умеет только ReactNode и\\n * ComponentType; всё остальное (например узел RenderSchema) отдаётся сюда — так компонент\\n * не импортирует рендерер, а получает его как зависимость.\\n *\\n * @example\\n * ```tsx\\n * renderStepBody={(body, form) => <RenderNodeComponent node={body} form={form} />}\\n * ```\\n */\\n renderStepBody?: (body: TBody, form: FormProxy<T>) => ReactNode;\\n}","summary":"Пропсы {@link FormWizard}.","description":"Пропсы {@link FormWizard}. Расширяют headless-пропсы из\\n`@reformer/cdk/form-wizard` (`form`, `config`, `onStepChange`, …), добавляя\\nдекларативный `steps` и колбэк `onSubmit`.","params":[],"examplesCount":0,"related":["FormWizardStep"],"sourcePath":"src/components/form-wizard/variants/base/form-wizard.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"FormWizardStep","kind":"interface","signature":"export interface FormWizardStep<T, TBody = never> {\\n /** Порядковый номер шага (1-based). Уникальный, задаёт порядок навигации. */\\n number: number;\\n /** Заголовок шага, показывается в {@link StepIndicator}. */\\n title: string;\\n /** Иконка шага (эмодзи или строка). Передаётся в headless Indicator. */\\n icon?: string;\\n /** Тело шага — FC | ReactNode | TBody (см. {@link FormWizardStepBody}). */\\n body: FormWizardStepBody<T, TBody>;\\n}","summary":"Описание одного шага {@link FormWizard}: порядковый номер, заголовок и иконка для индикатора, плюс полиморфное тело {@link FormWizardStepBody}.","description":"Описание одного шага {@link FormWizard}: порядковый номер, заголовок и иконка\\nдля индикатора, плюс полиморфное тело {@link FormWizardStepBody}.\\n\\nМассив `FormWizardStep<T>[]` передаётся в проп `steps`. Порядок и `number`\\nзадают последовательность навигации; `number` должен быть 1-based и уникальным.","params":[],"example":"Массив шагов кредитной заявки\\n```tsx\\nconst STEPS: FormWizardStep<CreditApplication>[] = [\\n{ number: 1, title: \'Кредит\', icon: \'💰\', body: BasicInfoForm },\\n{ number: 2, title: \'Данные\', icon: \'👤\', body: PersonalInfoForm },\\n{ number: 3, title: \'Подтверждение\', icon: \'✓\', body: ConfirmationForm },\\n];\\n```","examplesCount":1,"topics":["form-wizard"],"sourcePath":"src/components/form-wizard/variants/base/form-wizard.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit","usage":2},{"name":"FormWizardStepBody","kind":"type","signature":"export type FormWizardStepBody<T, TBody = never> =\\n | ComponentType<{ control: FormProxy<T> }>\\n | ReactNode\\n | TBody;","summary":"Полиморфное тело шага {@link FormWizardStep}.","description":"Полиморфное тело шага {@link FormWizardStep}. Один и тот же {@link FormWizard}\\nпокрывает TS-flow, renderer-react и renderer-json за счёт трёх допустимых форм\\n`body`, дискриминация которых выполняется в рантайме по типу значения:\\n\\n- `ComponentType<{ control: FormProxy<T> }>` — React-компонент; получает\\n `control={form}` (корневой {@link FormProxy}) и сам обращается к нужным полям.\\n- `ReactNode` — готовый JSX или статический контент шага (текст, число и т.п.).\\n- `TBody` — расширение под внешний рендерер (например `RenderNode<T>` из\\n `@reformer/renderer-react`); отрисовывается стратегией {@link FormWizardProps.renderStepBody}.","params":[],"example":"Компонент шага получает control\\n```tsx\\nfunction BasicInfoForm({ control }: { control: FormProxy<CreditApplication> }) {\\nreturn <FormField control={control.loanAmount} testId=\\"loanAmount\\" />;\\n}\\nconst body: FormWizardStepBody<CreditApplication> = BasicInfoForm;\\n```","examplesCount":2,"sourcePath":"src/components/form-wizard/variants/base/form-wizard.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"HoverCard","kind":"function","signature":"function HoverCard({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/hover-card/variants/base/hover-card-base.tsx","entries":[".","./hover-card"],"package":"@reformer/ui-kit"},{"name":"hoverCardBasePropsSchema","kind":"const","signature":"export const hoverCardBasePropsSchema","summary":"Props-схема HoverCard (Radix HoverCard.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/размеры — на HoverCardContent).","description":"Props-схема HoverCard (Radix HoverCard.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className\\n(стили/размеры — на HoverCardContent). Управляемое состояние (open/onOpenChange) — runtime, не в схеме.\\nОстаются задержки открытия/закрытия и неуправляемый defaultOpen.","params":[],"examplesCount":0,"sourcePath":"src/components/hover-card/variants/base/hover-card-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"HoverCardContent","kind":"function","signature":"function HoverCardContent({\\n className,\\n align = \'center\',\\n sideOffset = 4,\\n ...props\\n}: React.ComponentProps<typeof HoverCardPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/hover-card/variants/base/hover-card-base.tsx","entries":[".","./hover-card"],"package":"@reformer/ui-kit"},{"name":"HoverCardTrigger","kind":"function","signature":"function HoverCardTrigger({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/hover-card/variants/base/hover-card-base.tsx","entries":[".","./hover-card"],"package":"@reformer/ui-kit"},{"name":"Icon","kind":"function","signature":"function Icon({ iconName = \'Circle\', size = 24, color, strokeWidth = 2, className }: IconProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/icon/variants/base/icon-base.tsx","entries":[".","./icon"],"package":"@reformer/ui-kit"},{"name":"iconBasePropsSchema","kind":"const","signature":"export const iconBasePropsSchema","summary":"Props-схема презентационного `Icon` — единый источник api/props и валидации `componentProps`.","description":"Props-схема презентационного `Icon` — единый источник api/props и валидации `componentProps`.\\n`x-registryName: \'Icon\'` — каноническое имя в реестре renderer-json. Иконка задаётся строкой-именем\\nlucide (`iconName`); билдер рендерит для этого поля пикер иконок (виджет по ключу `iconName`).","params":[],"examplesCount":0,"sourcePath":"src/components/icon/variants/base/icon-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"IconProps","kind":"interface","signature":"export interface IconProps {\\n /** Имя иконки lucide (PascalCase, напр. `Home`, `ArrowRight`). */\\n iconName?: string;\\n /** Размер в пикселях. */\\n size?: number;\\n /** Цвет обводки (любой CSS-цвет; по умолчанию `currentColor`). */\\n color?: string;\\n /** Толщина линий. */\\n strokeWidth?: number;\\n /** Доп. CSS-класс. */\\n className?: string;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/icon/variants/base/icon-base.tsx","entries":[".","./icon"],"package":"@reformer/ui-kit"},{"name":"Input","kind":"function","signature":"function Input({ className, type, ...props }: React.ComponentProps<\'input\'>)","summary":"","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields","layout-and-buttons","form-field-integration","troubleshooting","form-array-section","input-mask"],"sourcePath":"src/components/input/variants/base/input-base.tsx","entries":[".","./input"],"package":"@reformer/ui-kit","usage":11},{"name":"InputBaseField","kind":"const","signature":"export const InputBaseField","summary":"Строковое поле: pure Input + nativeInputAdapter (e.target.value || null).","description":"Строковое поле: pure Input + nativeInputAdapter (e.target.value || null).","params":[],"examplesCount":0,"sourcePath":"src/components/input/variants/base/input-base.field.tsx","entries":[".","./input"],"package":"@reformer/ui-kit"},{"name":"inputBasePropsSchema","kind":"const","signature":"export const inputBasePropsSchema","summary":"Props-схема Input.","description":"Props-схема Input. `type` enum включает `number` и `date` (боевая форма использует `type: \'date\'` ×4 —\\nv6-контракт их не заявлял, из-за чего JSON-DSL пропускал невалид). `x-registryName: \'Input\'` — алиас InputField.","params":[],"examplesCount":0,"sourcePath":"src/components/input/variants/base/input-base.props.ts","entries":[".","./meta","./input"],"package":"@reformer/ui-kit"},{"name":"InputField","kind":"const","signature":"export const InputField","summary":"Field-версия Input — диспетчер по `type`: `number` → буфер (InputNumberField), иначе строковый (InputBaseField).","description":"Field-версия Input — диспетчер по `type`: `number` → буфер (InputNumberField),\\nиначе строковый (InputBaseField). Экспортируется как алиас `InputField`.\\n\\n`forwardRef`: оба пути форвардят ref и отдают baseline {@link FieldHandle} — строковый через\\n{@link InputBaseField} (HOC), числовой через собственный `useImperativeHandle` в\\n{@link InputNumberField}.","params":[],"examplesCount":0,"topics":["overview","text-fields","layout-and-buttons","form-field-integration","form-wizard","imperative-handles"],"sourcePath":"src/components/input/input-field.tsx","entries":[".","./input"],"package":"@reformer/ui-kit","usage":134},{"name":"InputGroup","kind":"function","signature":"function InputGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"InputGroupAddon","kind":"function","signature":"function InputGroupAddon({\\n className,\\n align = \'inline-start\',\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof inputGroupAddonVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"inputGroupBasePropsSchema","kind":"const","signature":"export const inputGroupBasePropsSchema","summary":"Props-схема `InputGroup` — единый источник `api`/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема `InputGroup` — единый источник `api`/props (reformer-doc) и валидации\\n`componentProps` (renderer-json). `InputGroup` — презентационная обёртка над `<div role=\\"group\\">`\\n(композиция контролов с аддонами), не form-control: нет seam (`value`/`onChange`/`onBlur`/\\n`disabled`), поэтому нет `x-runtimeProps`. Единственный сериализуемый проп самого контейнера —\\n`className`; под-компоненты (InputGroupAddon/InputGroupButton/…) и их дочерние ноды приходят из\\n`children[]` схемы рендера, а не из `componentProps`.\\n\\n`additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'InputGroup\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"InputGroupButton","kind":"function","signature":"function InputGroupButton({\\n className,\\n type = \'button\',\\n variant = \'ghost\',\\n size = \'xs\',\\n ...props\\n}: Omit<React.ComponentProps<typeof Button>, \'size\'> &\\n VariantProps<typeof inputGroupButtonVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"InputGroupInput","kind":"function","signature":"function InputGroupInput({ className, ...props }: React.ComponentProps<\'input\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"InputGroupText","kind":"function","signature":"function InputGroupText({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"InputGroupTextarea","kind":"function","signature":"function InputGroupTextarea({ className, ...props }: React.ComponentProps<\'textarea\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-group/variants/base/input-group-base.tsx","entries":[".","./input-group"],"package":"@reformer/ui-kit"},{"name":"InputMask","kind":"const","signature":"const InputMask","summary":"Текстовое поле с поддержкой простой маски-подсказки (через шаблон вида `\'9\'` для цифр).","description":"Текстовое поле с поддержкой простой маски-подсказки (через шаблон вида\\n`\'9\'` для цифр). Маска показывается в `placeholder`, но автоматическая\\nвставка литералов **не** выполняется — компонент просто помечает формат.\\n\\nРендерит canonical shadcn {@link Input} (`@/components/input`), надстраивая\\nvalue-based контракт (`value: string | null` / `onChange(string | null)` / `onBlur`).","params":[],"example":"Маска для телефона\\n```tsx\\nimport { InputMask } from \'@reformer/ui-kit\';\\n\\n<InputMask\\nvalue={phone}\\nonChange={setPhone}\\nmask=\\"+7 (999) 999-99-99\\"\\n/>\\n```","examplesCount":2,"topics":["overview","text-fields","choice-fields","form-field-integration","troubleshooting","input-mask"],"sourcePath":"src/components/input-mask/variants/base/input-mask-base.tsx","entries":[".","./input-mask"],"package":"@reformer/ui-kit","usage":3},{"name":"InputMaskBaseField","kind":"const","signature":"export const InputMaskBaseField","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-mask/variants/base/input-mask-base.field.tsx","entries":[".","./input-mask"],"package":"@reformer/ui-kit"},{"name":"inputMaskBasePropsSchema","kind":"const","signature":"export const inputMaskBasePropsSchema","summary":"Props-схема InputMask.","description":"Props-схема InputMask. Реальная поверхность в DSL — `mask`/`placeholder`/`className`;\\n`value`/`onChange`/`onBlur`/`disabled` приходят из seam (`mergeFieldPropsSchema`).\\n`additionalProperties: false` ловит опечатки `componentProps`.\\n`x-registryName: \'InputMask\'` — на этот вариант смотрит алиас `InputMaskField`.","params":[],"examplesCount":0,"sourcePath":"src/components/input-mask/variants/base/input-mask-base.props.ts","entries":[".","./meta","./input-mask"],"package":"@reformer/ui-kit"},{"name":"InputMaskField","kind":"const","signature":"export const InputMaskBaseField","summary":"","params":[],"examplesCount":0,"topics":["overview","text-fields","form-field-integration","input-mask"],"sourcePath":"src/components/input-mask/variants/base/input-mask-base.field.tsx","entries":[".","./input-mask"],"package":"@reformer/ui-kit","usage":37},{"name":"InputMaskProps","kind":"interface","signature":"export interface InputMaskProps extends Omit<\\n React.InputHTMLAttributes<HTMLInputElement>,\\n \'value\' | \'onChange\' | \'defaultValue\'\\n> {\\n /** Дополнительный CSS-класс. */\\n className?: string;\\n /** Текущее значение поля. `null`/`undefined` рендерится как пустое поле. */\\n value?: string | null;\\n /** Обработчик изменений. Пустая строка приводится к `null`. */\\n onChange?: (value: string | null) => void;\\n /** Срабатывает при потере фокуса. */\\n onBlur?: () => void;\\n /**\\n * Шаблон маски: символ `\'9\'` означает «цифра», все остальные символы (`+`,\\n * `-`, `(`, `)`, пробел, точка) — литералы и используются в `placeholder`.\\n * Пример: `\'+7 (999) 999-99-99\'`.\\n */\\n mask?: string;\\n /** Подсказка внутри поля. По умолчанию равна `mask` для подсветки формата. */\\n placeholder?: string;\\n /** Блокирует ввод и редактирование. */\\n disabled?: boolean;\\n}","summary":"Props компонента {@link InputMask}.","description":"Props компонента {@link InputMask}.","params":[],"examplesCount":0,"topics":["text-fields"],"sourcePath":"src/components/input-mask/variants/base/input-mask-base.tsx","entries":[".","./input-mask"],"package":"@reformer/ui-kit"},{"name":"InputNumberField","kind":"const","signature":"export const InputNumberField","summary":"Числовое поле (`type=\\"number\\"`): stateful-обёртка над pure `Input` с сырым строковым буфером.","description":"Числовое поле (`type=\\"number\\"`): stateful-обёртка над pure `Input` с сырым строковым буфером.\\nБуфер удерживает промежуточные/неканонические состояния ввода («1.», «1.50», «0.05», «-», ведущие\\nнули), которые схлопнулись бы при round-trip через `Number(...).toString()`. Логику держим байт-в-байт\\nс v6 (`input-number-buffer.ts` перенесён из carry; его тесты — guard).\\n\\nValue-based контракт seam: `value: number | null`, `onChange(number | null)` — number-буфер живёт здесь,\\nа не в примитиве (примитив остаётся pure), поэтому этот вариант не проходит через generic withFormControl.\\n\\n`forwardRef`: вариант минует HOC, поэтому baseline {@link FieldHandle} собирает сам —\\nтем же {@link makeElementFieldHandle}, что и `withFormControl`.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/input/variants/number/input-number.field.tsx","entries":[".","./input"],"package":"@reformer/ui-kit"},{"name":"InputOTP","kind":"function","signature":"function InputOTP({\\n className,\\n containerClassName,\\n ...props\\n}: React.ComponentProps<typeof OTPInput> & {\\n containerClassName?: string;\\n})","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/input-otp/variants/base/input-otp-base.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputOTPBaseField","kind":"const","signature":"export const InputOTPBaseField","summary":"OTP-поле: `InputOTP` (дефолтная раскладка слотов) + строковый `otpAdapter`.","description":"OTP-поле: `InputOTP` (дефолтная раскладка слотов) + строковый `otpAdapter`. Алиас `InputOTPField`.","params":[],"examplesCount":0,"sourcePath":"src/components/input-otp/variants/base/input-otp-base.field.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"inputOtpBasePropsSchema","kind":"const","signature":"export const inputOtpBasePropsSchema","summary":"Props-схема InputOTP — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема InputOTP — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Реальная поверхность в DSL — 2 ключа (`maxLength`/`className`);\\n`additionalProperties: false` ловит опечатки (враппер подмешивает label/required/…).\\n\\n`x-registryName: \'InputOTP\'` — на этот вариант смотрит алиас `InputOTPField`.","params":[],"examplesCount":0,"sourcePath":"src/components/input-otp/variants/base/input-otp-base.props.ts","entries":["./meta","./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputOTPField","kind":"const","signature":"export const InputOTPBaseField","summary":"OTP-поле: `InputOTP` (дефолтная раскладка слотов) + строковый `otpAdapter`.","description":"OTP-поле: `InputOTP` (дефолтная раскладка слотов) + строковый `otpAdapter`. Алиас `InputOTPField`.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/input-otp/variants/base/input-otp-base.field.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputOTPGroup","kind":"function","signature":"function InputOTPGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-otp/variants/base/input-otp-base.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputOTPSeparator","kind":"function","signature":"function InputOTPSeparator({ ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-otp/variants/base/input-otp-base.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputOTPSlot","kind":"function","signature":"function InputOTPSlot({\\n index,\\n className,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n index: number;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/input-otp/variants/base/input-otp-base.tsx","entries":["./input-otp"],"package":"@reformer/ui-kit"},{"name":"InputPassword","kind":"const","signature":"const InputPassword","summary":"Поле ввода пароля с переключателем видимости (иконка eye/eye-off).","description":"Поле ввода пароля с переключателем видимости (иконка eye/eye-off).\\nКнопка переключения показывается, когда `showToggle = true` (по умолчанию)\\nи `value` непустой.","params":[],"example":"С переключателем видимости\\n```tsx\\nimport { InputPassword } from \'@reformer/ui-kit\';\\n\\n<InputPassword\\nvalue={password}\\nonChange={setPassword}\\nplaceholder=\\"Пароль\\"\\n/>\\n```","examplesCount":2,"topics":["overview","text-fields","choice-fields","troubleshooting"],"sourcePath":"src/components/input-password/variants/base/input-password-base.tsx","entries":[".","./input-password"],"package":"@reformer/ui-kit","usage":3},{"name":"InputPasswordBaseField","kind":"const","signature":"export const InputPasswordBaseField","summary":"Поле пароля: value-based InputPassword + identity-адаптер.","description":"Поле пароля: value-based InputPassword + identity-адаптер.\\n`exposesHandle: true` — InputPassword сам реализует {@link InputPasswordHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"sourcePath":"src/components/input-password/variants/base/input-password-base.field.tsx","entries":[".","./input-password"],"package":"@reformer/ui-kit"},{"name":"inputPasswordBasePropsSchema","kind":"const","signature":"export const inputPasswordBasePropsSchema","summary":"Props-схема InputPassword — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема InputPassword — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Реальная поверхность в DSL — 3 ключа; `additionalProperties: false`\\nловит опечатки (`lable` вместо `label` подмешивается враппером).\\n\\n`x-registryName: \'InputPassword\'` — на эту схему смотрит алиас `InputPasswordField`.","params":[],"examplesCount":0,"sourcePath":"src/components/input-password/variants/base/input-password-base.props.ts","entries":[".","./meta","./input-password"],"package":"@reformer/ui-kit"},{"name":"InputPasswordField","kind":"const","signature":"export const InputPasswordBaseField","summary":"Поле пароля: value-based InputPassword + identity-адаптер.","description":"Поле пароля: value-based InputPassword + identity-адаптер.\\n`exposesHandle: true` — InputPassword сам реализует {@link InputPasswordHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"topics":["overview","text-fields","imperative-handles"],"sourcePath":"src/components/input-password/variants/base/input-password-base.field.tsx","entries":[".","./input-password"],"package":"@reformer/ui-kit","usage":11},{"name":"InputPasswordHandle","kind":"interface","signature":"export interface InputPasswordHandle extends FieldHandle {\\n /** Переключить видимость пароля (password ↔ text). */\\n toggleVisibility(): void;\\n /** Задать видимость пароля явно. */\\n setVisible(visible: boolean): void;\\n}","summary":"Императивный handle {@link InputPassword}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/ getElement на нативном input) + управление видимостью пароля.","description":"Императивный handle {@link InputPassword}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/\\ngetElement на нативном input) + управление видимостью пароля. Достаётся из схемы:\\n`schema.node(\'password\').getRef<InputPasswordHandle>().current?.setVisible(true)`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/input-password/variants/base/input-password-base.tsx","entries":[".","./input-password"],"package":"@reformer/ui-kit","usage":2},{"name":"InputPasswordProps","kind":"interface","signature":"export interface InputPasswordProps extends Omit<\\n React.InputHTMLAttributes<HTMLInputElement>,\\n \'value\' | \'onChange\' | \'type\' | \'defaultValue\'\\n> {\\n /** Дополнительный CSS-класс. */\\n className?: string;\\n /** Текущее значение пароля. `null`/`undefined` рендерится как пустое поле. */\\n value?: string | null;\\n /** Обработчик изменений. Пустая строка приводится к `null`. */\\n onChange?: (value: string | null) => void;\\n /** Срабатывает при потере фокуса. */\\n onBlur?: () => void;\\n /** Подсказка внутри поля. По умолчанию `\'Password\'`. */\\n placeholder?: string;\\n /** Блокирует ввод. */\\n disabled?: boolean;\\n /**\\n * Показывать ли иконку переключения видимости (eye/eye-off). По умолчанию\\n * `true`. Иконка появляется только когда `value` непустой.\\n */\\n showToggle?: boolean;\\n}","summary":"Props компонента {@link InputPassword}.","description":"Props компонента {@link InputPassword}.","params":[],"examplesCount":0,"topics":["text-fields"],"sourcePath":"src/components/input-password/variants/base/input-password-base.tsx","entries":[".","./input-password"],"package":"@reformer/ui-kit"},{"name":"isBranch","kind":"function","signature":"export function isBranch(node: TreeNode): boolean","summary":"Ветка ли узел.","description":"Ветка ли узел. Правило одно на всё дерево — и на отрисовку, и на клавиатуру.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"Item","kind":"function","signature":"function Item({\\n className,\\n variant = \'default\',\\n size = \'default\',\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof itemVariants> & { asChild?: boolean })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemActions","kind":"function","signature":"function ItemActions({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"itemBasePropsSchema","kind":"const","signature":"export const itemBasePropsSchema","summary":"Props-схема Item — контейнер-строка списка (рендерит div со стилями cva variant/size).","description":"Props-схема Item — контейнер-строка списка (рендерит div со стилями cva variant/size).","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ItemContent","kind":"function","signature":"function ItemContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemDescription","kind":"function","signature":"function ItemDescription({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemFooter","kind":"function","signature":"function ItemFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemGroup","kind":"function","signature":"function ItemGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemHeader","kind":"function","signature":"function ItemHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemMedia","kind":"function","signature":"function ItemMedia({\\n className,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<\'div\'> & VariantProps<typeof itemMediaVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"itemMediaVariants","kind":"const","signature":"const itemMediaVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemSeparator","kind":"function","signature":"function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"ItemTitle","kind":"function","signature":"function ItemTitle({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"itemVariants","kind":"const","signature":"const itemVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/item/variants/base/item-base.tsx","entries":[".","./item"],"package":"@reformer/ui-kit"},{"name":"Kbd","kind":"function","signature":"function Kbd({ className, ...props }: React.ComponentProps<\'kbd\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/kbd/variants/base/kbd-base.tsx","entries":[".","./kbd"],"package":"@reformer/ui-kit"},{"name":"kbdBasePropsSchema","kind":"const","signature":"export const kbdBasePropsSchema","summary":"Props-схема Kbd — презентационный <kbd> (порт shadcn/ui) для отображения клавиш.","description":"Props-схема Kbd — презентационный <kbd> (порт shadcn/ui) для отображения клавиш.\\nБез Radix и состояния: единственный статический проп — className, всё\\nостальное (children/ref/DOM-атрибуты) несериализуемо и в схему не входит.","params":[],"examplesCount":0,"sourcePath":"src/components/kbd/variants/base/kbd-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"KbdGroup","kind":"function","signature":"function KbdGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/kbd/variants/base/kbd-base.tsx","entries":[".","./kbd"],"package":"@reformer/ui-kit"},{"name":"Label","kind":"function","signature":"function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["form-field-integration"],"sourcePath":"src/components/label/variants/base/label-base.tsx","entries":[".","./label"],"package":"@reformer/ui-kit"},{"name":"labelBasePropsSchema","kind":"const","signature":"export const labelBasePropsSchema","summary":"Props-схема презентационного `Label` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Label` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Label\'` — каноническое имя в реестре renderer-json.\\n`Label` — дословный порт shadcn поверх Radix `LabelPrimitive.Root` (рендерит `<label>`):\\nсериализуемые пропсы — `className` + нативный `htmlFor`.","params":[],"examplesCount":0,"sourcePath":"src/components/label/variants/base/label-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"List","kind":"function","signature":"export function List({ items = [], className, testId, as: As = \'div\' }: ListProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/list/variants/base/list.tsx","entries":[".","./list"],"package":"@reformer/ui-kit","usage":9},{"name":"ListProps","kind":"interface","signature":"export interface ListProps {\\n /** Отрендеренные элементы массива (инъектится рендерером). */\\n items?: ArrayItemSlot[];\\n /** CSS-класс контейнера (мержится поверх дефолтного `space-y-2`). */\\n className?: string;\\n /** `data-testid` контейнера. */\\n testId?: string;\\n /** Тег/компонент обёртки. По умолчанию `\'div\'`. */\\n as?: ElementType;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/list/variants/base/list.tsx","entries":[".","./list"],"package":"@reformer/ui-kit"},{"name":"makeElementFieldHandle","kind":"function","signature":"export function makeElementFieldHandle(el: RefObject<HTMLElement | null>): FieldHandle","summary":"Собирает baseline {@link FieldHandle}, делегирующий на DOM-элемент по ссылке `el`.","description":"Собирает baseline {@link FieldHandle}, делегирующий на DOM-элемент по ссылке `el`.\\nВсе вызовы null-safe: до монтирования (`el.current === null`) — no-op, без исключений.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/field-handle.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"Marker","kind":"function","signature":"function Marker({\\n className,\\n variant = \'default\',\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'div\'> &\\n VariantProps<typeof markerVariants> & {\\n asChild?: boolean;\\n })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/marker/variants/base/marker-base.tsx","entries":[".","./marker"],"package":"@reformer/ui-kit"},{"name":"markerBasePropsSchema","kind":"const","signature":"export const markerBasePropsSchema","summary":"Props-схема Marker (AI-примитив, порт shadcn/ui) — рендерит DOM-элемент <div> и пробрасывает className, поэтому className в схеме.","description":"Props-схема Marker (AI-примитив, порт shadcn/ui) — рендерит DOM-элемент <div> и пробрасывает\\nclassName, поэтому className в схеме. Единственный enum — variant (стиль оформления маркера).","params":[],"examplesCount":0,"sourcePath":"src/components/marker/variants/base/marker-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"MarkerContent","kind":"function","signature":"function MarkerContent({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/marker/variants/base/marker-base.tsx","entries":[".","./marker"],"package":"@reformer/ui-kit"},{"name":"MarkerIcon","kind":"function","signature":"function MarkerIcon({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/marker/variants/base/marker-base.tsx","entries":[".","./marker"],"package":"@reformer/ui-kit"},{"name":"markerVariants","kind":"const","signature":"const markerVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/marker/variants/base/marker-base.tsx","entries":[".","./marker"],"package":"@reformer/ui-kit"},{"name":"Menubar","kind":"function","signature":"function Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"menubarBasePropsSchema","kind":"const","signature":"export const menubarBasePropsSchema","summary":"Props-схема Menubar (Radix Menubar.Root) — рендерит DOM-контейнер меню-бара, поэтому несёт className.","description":"Props-схема Menubar (Radix Menubar.Root) — рендерит DOM-контейнер меню-бара, поэтому несёт\\nclassName. Управляемое состояние (value/onValueChange/defaultValue — какое меню открыто) — runtime,\\nв схему не входит. Статически задаются только направление (dir) и зацикливание фокуса (loop).","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"MenubarCheckboxItem","kind":"function","signature":"function MenubarCheckboxItem({\\n className,\\n children,\\n checked,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarContent","kind":"function","signature":"function MenubarContent({\\n className,\\n align = \'start\',\\n alignOffset = -4,\\n sideOffset = 8,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarGroup","kind":"function","signature":"function MenubarGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Group>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarItem","kind":"function","signature":"function MenubarItem({\\n className,\\n inset,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.Item> & {\\n inset?: boolean;\\n variant?: \'default\' | \'destructive\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarLabel","kind":"function","signature":"function MenubarLabel({\\n className,\\n inset,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.Label> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarMenu","kind":"function","signature":"function MenubarMenu({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Menu>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarPortal","kind":"function","signature":"function MenubarPortal({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarRadioGroup","kind":"function","signature":"function MenubarRadioGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarRadioItem","kind":"function","signature":"function MenubarRadioItem({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarSeparator","kind":"function","signature":"function MenubarSeparator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarShortcut","kind":"function","signature":"function MenubarShortcut({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarSub","kind":"function","signature":"function MenubarSub({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Sub>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarSubContent","kind":"function","signature":"function MenubarSubContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.SubContent>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarSubTrigger","kind":"function","signature":"function MenubarSubTrigger({\\n className,\\n inset,\\n children,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {\\n inset?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"MenubarTrigger","kind":"function","signature":"function MenubarTrigger({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MenubarPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/menubar/variants/base/menubar-base.tsx","entries":[".","./menubar"],"package":"@reformer/ui-kit"},{"name":"mergeFieldPropsSchema","kind":"function","signature":"export function mergeFieldPropsSchema(variantSchema: PropsSchema): PropsSchema","summary":"Полная схема `componentProps` field-ноды: контракт враппера + seam + вариант.","description":"Полная схема `componentProps` field-ноды: контракт враппера + seam + вариант.\\n\\nИменно структурный merge `properties`, а НЕ `allOf: [wrapper, variant]`: в draft-07\\n`additionalProperties` смотрит только на `properties` СВОЕЙ схемы → в `allOf` каждая ветка\\nотвергла бы props соседней. Строгость решает вариант своим `additionalProperties`.","params":[],"examplesCount":0,"sourcePath":"src/fields/props-schema.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"Message","kind":"function","signature":"function Message({\\n className,\\n align = \'start\',\\n ...props\\n}: React.ComponentProps<\'div\'> & { align?: \'start\' | \'end\' })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"MessageAvatar","kind":"function","signature":"function MessageAvatar({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"messageBasePropsSchema","kind":"const","signature":"export const messageBasePropsSchema","summary":"Props-схема Message (shadcn AI chat message) — контейнер одного сообщения (обычный <div>, пробрасывает className).","description":"Props-схема Message (shadcn AI chat message) — контейнер одного сообщения (обычный <div>,\\nпробрасывает className). Из статики есть только выравнивание строки и className;\\nchildren/аватар/заголовок задаются вложенными под-частями, не пропсами.","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"MessageContent","kind":"function","signature":"function MessageContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"MessageFooter","kind":"function","signature":"function MessageFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"MessageGroup","kind":"function","signature":"function MessageGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"MessageHeader","kind":"function","signature":"function MessageHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message/variants/base/message-base.tsx","entries":[".","./message"],"package":"@reformer/ui-kit"},{"name":"MessageScroller","kind":"function","signature":"function MessageScroller({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"messageScrollerBasePropsSchema","kind":"const","signature":"export const messageScrollerBasePropsSchema","summary":"Props-схема MessageScroller (Root примитива","description":"Props-схема MessageScroller (Root примитива","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"MessageScrollerButton","kind":"function","signature":"function MessageScrollerButton({\\n direction = \'end\',\\n className,\\n children,\\n render,\\n variant = \'secondary\',\\n size = \'icon-sm\',\\n ...props\\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\\n Pick<React.ComponentProps<typeof Button>, \'variant\' | \'size\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"MessageScrollerContent","kind":"function","signature":"function MessageScrollerContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"MessageScrollerItem","kind":"function","signature":"function MessageScrollerItem({\\n className,\\n scrollAnchor = false,\\n ...props\\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"MessageScrollerProvider","kind":"function","signature":"function MessageScrollerProvider(\\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>\\n)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"MessageScrollerViewport","kind":"function","signature":"function MessageScrollerViewport({\\n className,\\n ...props\\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/message-scroller/variants/base/message-scroller-base.tsx","entries":["./message-scroller"],"package":"@reformer/ui-kit"},{"name":"multiValueAdapter","kind":"const","signature":"export const multiValueAdapter: FieldAdapter","summary":"Мультивыбор (`SelectMulti` / `ComboboxMulti` / `NativeSelectMulti` / `ToggleGroupMulti`) — value-based `value: string[] | null` + `onChange(string[] | null)`.","description":"Мультивыбор (`SelectMulti` / `ComboboxMulti` / `NativeSelectMulti` / `ToggleGroupMulti`) —\\nvalue-based `value: string[] | null` + `onChange(string[] | null)`.\\n\\nПустой выбор нормализуется в `null`, а не в `[]`. Причина не косметическая: начальным значением\\nполя в модели массив быть НЕ МОЖЕТ — `createModel({ tags: [] })` строит ArrayNode, `createForm`\\nтакой путь пропускает, и поля не появляется вовсе (в renderer оно при этом тихо отрендерится\\nконтейнером — с подписью и опциями, но без value/onChange). Поэтому поле живёт как\\n`string[] | null`, и `required()` ловит пустой выбор без правок ядра. Тот же приём и по той же\\nпричине — у `fileUploadAdapter` (file-upload-base.field.tsx).\\n\\n`fromEmit` копирует массив: preact-сигнал бэйлится по `!==`, поэтому контрол, вернувший\\nмутированный на месте массив, подписчиков бы не уведомил — а `_dirty` при этом уже взвёлся бы.\\nКопия делает такой контрол безопасным.\\n\\n`toValue` отдаёт массив (`null` → `[]`): мульти-презентации ходят по значению `.map`/`.includes`,\\nи `\'\'` от `valueChangeAdapter` их бы уронил.","params":[],"examplesCount":0,"topics":["choice-fields","imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit","usage":1},{"name":"nativeInputAdapter","kind":"const","signature":"export const nativeInputAdapter: FieldAdapter","summary":"Input / Textarea / Native Select — нативный `onChange(e)` → `e.target.value`.","description":"Input / Textarea / Native Select — нативный `onChange(e)` → `e.target.value`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"NativeSelect","kind":"function","signature":"function NativeSelect({\\n className,\\n size = \'default\',\\n ...props\\n}: Omit<React.ComponentProps<\'select\'>, \'size\'> & { size?: \'sm\' | \'default\' })","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/native-select/variants/base/native-select-base.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectBaseField","kind":"const","signature":"export const NativeSelectBaseField","summary":"Field-версия NativeSelect: `NativeSelectWithOptions` (options → `<option>`) + `nativeInputAdapter` (`e.target.value || null`).","description":"Field-версия NativeSelect: `NativeSelectWithOptions` (options → `<option>`) + `nativeInputAdapter`\\n(`e.target.value || null`). Экспортируется как алиас `NativeSelectField`.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"nativeSelectBasePropsSchema","kind":"const","signature":"export const nativeSelectBasePropsSchema","summary":"Props-схема NativeSelect — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема NativeSelect — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Стилизованный native `<select>`: значение — строка (`option.value`),\\nпустой выбор → null (nativeInputAdapter). `x-registryName: \'NativeSelect\'` — на него смотрит алиас\\n`NativeSelectField`.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.props.ts","entries":[".","./meta","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectField","kind":"const","signature":"export const NativeSelectBaseField","summary":"Field-версия NativeSelect: `NativeSelectWithOptions` (options → `<option>`) + `nativeInputAdapter` (`e.target.value || null`).","description":"Field-версия NativeSelect: `NativeSelectWithOptions` (options → `<option>`) + `nativeInputAdapter`\\n(`e.target.value || null`). Экспортируется как алиас `NativeSelectField`.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/native-select/variants/base/native-select-base.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectMulti","kind":"function","signature":"function NativeSelectMulti({\\n options = [],\\n value,\\n onChange,\\n rows,\\n maxItems,\\n className,\\n \'data-testid\': dataTestId,\\n ...props\\n}: NativeSelectMultiProps)","summary":"Нативный `<select multiple>` (вариант `multi`).","description":"Нативный `<select multiple>` (вариант `multi`).\\n\\nНЕ переиспользует примитив `NativeSelect`: тот — дословный порт shadcn под ОДНОСТРОЧНЫЙ select\\n(`h-9`, `pr-9` под абсолютно спозиционированный шеврон, а нативный атрибут `size` у него занят\\nпод ступень шкалы размеров и вырезан `Omit`\'ом). Листбоксу нужна принципиально другая геометрия,\\nпоэтому вариант рисует свой `<select>` и переиспользует из порта только `<option>`/`<optgroup>` —\\nтак порт остаётся без дрейфа от upstream.\\n\\nЧестное ограничение, которое надо знать до выбора этого контрола: на тач-устройствах\\nмножественный выбор в нативном листбоксе практически недоступен, аффорданса «можно несколько»\\nнет, и высота фиксирована. Для тач берите `ToggleGroupMulti` или `SelectMulti`;\\n`NativeSelectMulti` — путь для no-JS / legacy / киосков, где нужна нативная семантика и\\nклавиатура (Shift+стрелки, Ctrl+клик) без единой строки JS.\\n\\n`placeholder` здесь отсутствует намеренно: у одиночного варианта это `<option value=\\"\\">` в начале\\nсписка, а в multiple-листбоксе такая опция становится ВЫБИРАЕМЫМ мусорным пунктом.","params":[],"examplesCount":0,"topics":["choice-fields","troubleshooting"],"sourcePath":"src/components/native-select/variants/multi/native-select-multi.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit","usage":1},{"name":"NativeSelectMultiField","kind":"const","signature":"export const NativeSelectMultiField","summary":"Field-версия NativeSelectMulti: нативный множественный выбор со значением `string[] | null`.","description":"Field-версия NativeSelectMulti: нативный множественный выбор со значением `string[] | null`.\\nПривязка через {@link multiValueAdapter} — общий для всех мультивыборов кита.\\nШтатный `nativeInputAdapter` тут непригоден: он читает `e.target.value`, что у `<select multiple>`\\nдаёт только первое выбранное значение.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/native-select/variants/multi/native-select-multi.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit","usage":2},{"name":"NativeSelectMultiFieldProps","kind":"interface","signature":"export interface NativeSelectMultiFieldProps {\\n value?: string[] | null;\\n onChange?: (value: string[] | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n options?: NativeSelectOptionItem[];\\n rows?: number;\\n maxItems?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии NativeSelectMulti.","description":"Value-based контракт field-версии NativeSelectMulti. Значение — `string[] | null`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт `options`/`rows`/`maxItems`/`className`.\\nСлужит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/multi/native-select-multi.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectMultiProps","kind":"interface","signature":"export interface NativeSelectMultiProps {\\n /** Опции списка. Одинаковый `group` объединяется в `<optgroup>`. */\\n options?: NativeSelectOptionItem[];\\n /**\\n * Выбранные значения. Приходит массивом всегда: `multiValueAdapter` разворачивает `null` в `[]`.\\n * Нативный `<select multiple>` в управляемом режиме требует именно массив.\\n */\\n value?: string[];\\n /** Изменение выбора. Всегда получает НОВЫЙ массив — см. `multiValueAdapter`. */\\n onChange?: (value: string[]) => void;\\n onBlur?: () => void;\\n /**\\n * Число видимых строк (нативный атрибут `size`). По умолчанию браузер показывает 4.\\n *\\n * Проп называется `rows`, а не `size`: у остальных контролов кита `size` — это ступень шкалы\\n * размеров (`\'sm\' | \'default\'`), и одноимённый проп с другим смыслом читался бы как опечатка.\\n */\\n rows?: number;\\n /**\\n * Потолок числа выбранных: по достижении невыбранные опции выключаются.\\n * Affordance, а НЕ правило формы — ограничение задавайте валидатором `maxLength(n)`.\\n */\\n maxItems?: number;\\n className?: string;\\n disabled?: boolean;\\n /** id корневого элемента — по нему форма связывает подпись, описание и сообщение об ошибке. */\\n id?: string;\\n /** Префикс `data-testid`; на `<select>` + `-<value>` на каждый `<option>`. */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props презентационного {@link NativeSelectMulti}.","description":"Props презентационного {@link NativeSelectMulti}.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/multi/native-select-multi.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"nativeSelectMultiPropsSchema","kind":"const","signature":"export const nativeSelectMultiPropsSchema","summary":"Props-схема NativeSelectMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема NativeSelectMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'NativeSelectMulti\'` — отдельная запись каталога, а не проп у `NativeSelect`:\\nтип значения другой (`string[] | null` против `string | null`), а `x-runtimeProps.value` у\\nзаписи ровно один. Прецедент — `FileUpload` / `FileUploadAvatar`.\\n\\n`placeholder` отсутствует НАМЕРЕННО: у одиночного варианта это `<option value=\\"\\">` в начале\\nсписка, а в multiple-листбоксе такая опция становится выбираемым мусорным пунктом. Это\\nединственное вынужденное расхождение с общим набором пропсов мультивыборов кита.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/multi/native-select-multi.props.ts","entries":[".","./meta","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectOptGroup","kind":"function","signature":"function NativeSelectOptGroup({ className, ...props }: React.ComponentProps<\'optgroup\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectOption","kind":"function","signature":"function NativeSelectOption({ className, ...props }: React.ComponentProps<\'option\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectOptionItem","kind":"interface","signature":"export interface NativeSelectOptionItem {\\n value: string | number;\\n label: string;\\n group?: string;\\n}","summary":"Один пункт списка native select.","description":"Один пункт списка native select. Одинаковый `group` объединяется в `<optgroup>`.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectWithOptions","kind":"function","signature":"function NativeSelectWithOptions({\\n options = [],\\n placeholder,\\n ...props\\n}: NativeSelectWithOptionsProps)","summary":"Строит `<option>` из декларативного `options` (в отличие от JSX-children pure NativeSelect): form/renderer-json передают опции как сериализуемый `componentProps.options`.","description":"Строит `<option>` из декларативного `options` (в отличие от JSX-children pure NativeSelect):\\nform/renderer-json передают опции как сериализуемый `componentProps.options`. Опции с одинаковым\\n`group` объединяются в `<optgroup>` (порядок появления сохраняется).\\n\\n`data-testid`/`id`/`aria-*`/`value`/`onChange` уходят на `<select>` (Root примитива), НЕ на wrapper.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NativeSelectWithOptionsProps","kind":"interface","signature":"export interface NativeSelectWithOptionsProps extends Omit<\\n React.ComponentProps<typeof NativeSelect>,\\n \'children\'\\n> {\\n /** Опции списка. Строятся в `<option>` (сериализуемый источник для формы/DSL). */\\n options?: NativeSelectOptionItem[];\\n /** Подсказка-опция `value=\\"\\"` в начале списка (пустой выбор → null через адаптер). */\\n placeholder?: string;\\n}","summary":"Props враппера {@link NativeSelectWithOptions}: pure NativeSelect + декларативные `options`.","description":"Props враппера {@link NativeSelectWithOptions}: pure NativeSelect + декларативные `options`.","params":[],"examplesCount":0,"sourcePath":"src/components/native-select/variants/base/native-select-base.field.tsx","entries":[".","./native-select"],"package":"@reformer/ui-kit"},{"name":"NavigationMenu","kind":"function","signature":"function NavigationMenu({\\n className,\\n children,\\n viewport = true,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {\\n viewport?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"navigationMenuBasePropsSchema","kind":"const","signature":"export const navigationMenuBasePropsSchema","summary":"Props-схема NavigationMenu (Radix NavigationMenu.Root) — рендерит DOM-элемент <nav> и пробрасывает className, поэтому className входит в схему.","description":"Props-схема NavigationMenu (Radix NavigationMenu.Root) — рендерит DOM-элемент <nav> и пробрасывает\\nclassName, поэтому className входит в схему. Управляемое состояние (value/onValueChange) — runtime,\\nне в схеме. Сериализуемые статические пропсы: viewport, orientation, dir, тайминги задержек.","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuContent","kind":"function","signature":"function NavigationMenuContent({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuIndicator","kind":"function","signature":"function NavigationMenuIndicator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuItem","kind":"function","signature":"function NavigationMenuItem({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuLink","kind":"function","signature":"function NavigationMenuLink({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuList","kind":"function","signature":"function NavigationMenuList({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuTrigger","kind":"function","signature":"function NavigationMenuTrigger({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"navigationMenuTriggerStyle","kind":"const","signature":"const navigationMenuTriggerStyle","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NavigationMenuViewport","kind":"function","signature":"function NavigationMenuViewport({\\n className,\\n ...props\\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/navigation-menu/variants/base/navigation-menu-base.tsx","entries":[".","./navigation-menu"],"package":"@reformer/ui-kit"},{"name":"NormalizedOption","kind":"interface","signature":"export interface NormalizedOption {\\n id: string | number;\\n label: string;\\n value: string;\\n group?: string;\\n}","summary":"Нормализованная опция: `value` приведён к строке для Radix и `onChange`.","description":"Нормализованная опция: `value` приведён к строке для Radix и `onChange`.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"Pagination","kind":"function","signature":"function Pagination({ className, ...props }: React.ComponentProps<\'nav\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"paginationBasePropsSchema","kind":"const","signature":"export const paginationBasePropsSchema","summary":"Props-схема Pagination (презентационный `<nav role=\\"navigation\\">`, порт shadcn/ui).","description":"Props-схема Pagination (презентационный `<nav role=\\"navigation\\">`, порт shadcn/ui).\\nRoot — простой DOM-элемент, пробрасывает className; собственных сериализуемых\\nпропсов (enum/boolean/number) нет — только доп. CSS-класс.","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"PaginationContent","kind":"function","signature":"function PaginationContent({ className, ...props }: React.ComponentProps<\'ul\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"PaginationEllipsis","kind":"function","signature":"function PaginationEllipsis({ className, ...props }: React.ComponentProps<\'span\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"PaginationItem","kind":"function","signature":"function PaginationItem({ ...props }: React.ComponentProps<\'li\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"PaginationLink","kind":"function","signature":"function PaginationLink({ className, isActive, size = \'icon\', ...props }: PaginationLinkProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"PaginationNext","kind":"function","signature":"function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"PaginationPrevious","kind":"function","signature":"function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/pagination/variants/base/pagination-base.tsx","entries":[".","./pagination"],"package":"@reformer/ui-kit"},{"name":"Popover","kind":"function","signature":"function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit","usage":2},{"name":"PopoverAnchor","kind":"function","signature":"function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"popoverBasePropsSchema","kind":"const","signature":"export const popoverBasePropsSchema","summary":"Props-схема Popover (Radix Popover.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className (стили/позиционирование — на PopoverContent).","description":"Props-схема Popover (Radix Popover.Root) — контекст-провайдер без DOM, поэтому НЕ несёт className\\n(стили/позиционирование — на PopoverContent). Управляемое состояние (open/onOpenChange) — runtime, не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"PopoverContent","kind":"function","signature":"function PopoverContent({\\n className,\\n align = \'center\',\\n sideOffset = 4,\\n ...props\\n}: React.ComponentProps<typeof PopoverPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"PopoverDescription","kind":"function","signature":"function PopoverDescription({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"PopoverHeader","kind":"function","signature":"function PopoverHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"PopoverTitle","kind":"function","signature":"function PopoverTitle({ className, ...props }: React.ComponentProps<\'h2\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"PopoverTrigger","kind":"function","signature":"function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/popover/variants/base/popover-base.tsx","entries":[".","./popover"],"package":"@reformer/ui-kit"},{"name":"pressedAdapter","kind":"const","signature":"export const pressedAdapter: FieldAdapter","summary":"Toggle — Radix `pressed` + `onPressedChange(boolean)`.","description":"Toggle — Radix `pressed` + `onPressedChange(boolean)`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"Progress","kind":"function","signature":"function Progress({\\n className,\\n value,\\n ...props\\n}: React.ComponentProps<typeof ProgressPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["form-wizard"],"sourcePath":"src/components/progress/variants/base/progress-base.tsx","entries":[".","./progress"],"package":"@reformer/ui-kit","usage":1},{"name":"progressBasePropsSchema","kind":"const","signature":"export const progressBasePropsSchema","summary":"Props-схема `Progress` — единый источник `api`/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема `Progress` — единый источник `api`/props (reformer-doc) и валидации\\n`componentProps` (renderer-json). `Progress` — обёртка над Radix `Progress.Root` (Root+Indicator),\\nпрезентационный индикатор, не form-control: нет seam (`value`/`onChange`/`onBlur`/`disabled`),\\nпоэтому нет `x-runtimeProps`. `value` здесь — статичный проп отображения (не редактируемое\\nзначение поля). Сериализуемые пропсы — `className`, `value`, `max`.\\n\\n`additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'Progress\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/progress/variants/base/progress-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"PropDoc","kind":"interface","signature":"export interface PropDoc {\\n group: PropGroup;\\n /** Отображаемый TS-тип: JSON Schema не выражает `string | null` и сигнатуры функций. */\\n type: string;\\n /** Переопределить виджет. По умолчанию выводится из `type`/`enum`. */\\n kind?: PropWidget;\\n}","summary":"`x-doc` — ровно то, чего нет в словаре JSON Schema.","description":"`x-doc` — ровно то, чего нет в словаре JSON Schema. Остальное берётся из стандартных\\nключей: `description`, `default`, `enum`→options, `minimum`/`maximum`/`multipleOf`.","params":[],"examplesCount":0,"sourcePath":"src/fields/props-schema.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"PropsSchema","kind":"type","signature":"export type PropsSchema = Omit<\\n JSONSchema7,\\n \'properties\' | \'items\' | \'anyOf\' | \'additionalProperties\'\\n> & {\\n \'x-doc\'?: PropDoc;\\n \'x-runtimeProps\'?: Record<string, RuntimePropDoc>;\\n /**\\n * Каноническое имя в реестре renderer-json. Ставит вариант, на который смотрит алиас\\n * `<Cmp>Field`. По нему `generate-meta.mjs` собирает `defaultPropSchemas`.\\n */\\n \'x-registryName\'?: string;\\n /**\\n * Имя группы вариантов (напр. `\'Input\'`). Члены группы делят это имя; дефолт группы — член, чей\\n * `x-registryName === x-variantGroup`. Билдер по нему группирует палитру/QuickAdd/инспектор.\\n * ВНИМАНИЕ: `mergeFieldPropsSchema` не копирует `x-*` в merged-схему — генератор читает это из\\n * СЫРОГО варианта и кладёт как record-level поле каталога.\\n */\\n \'x-variantGroup\'?: string;\\n /** Человекочитаемая метка варианта в группе (напр. `\'Пароль\'`). */\\n \'x-variant\'?: string;\\n properties?: Record<string, PropsSchema>;\\n items?: PropsSchema | PropsSchema[];\\n anyOf?: PropsSchema[];\\n additionalProperties?: boolean | PropsSchema;\\n};","summary":"ВНИМАНИЕ: форма `Omit<…> & {…}` — не косметика.","description":"ВНИМАНИЕ: форма `Omit<…> & {…}` — не косметика. Именно интерсекция с mapped-типом\\nпропускает `as const`-значения (readonly-кортежи в `required`/`enum`). Плоский interface\\nна них ругается (проверено). Рефакторить — только с прогоном typecheck.","params":[],"examplesCount":0,"sourcePath":"src/fields/props-schema.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"PropWidget","kind":"type","signature":"export type PropWidget = \'boolean\' | \'text\' | \'number\' | \'enum\' | \'readonly\';","summary":"","params":[],"examplesCount":0,"sourcePath":"src/fields/props-schema.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"RadioGroup","kind":"function","signature":"function RadioGroup({\\n className,\\n ...props\\n}: React.ComponentProps<typeof RadioGroupPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields","troubleshooting"],"sourcePath":"src/components/radio-group/variants/base/radio-group-base.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit","usage":2},{"name":"RadioGroupBaseField","kind":"const","signature":"export const RadioGroupBaseField","summary":"Field-версия RadioGroup: value-based (`value: string | null`, `onChange(value)`), рендерит `options`.","description":"Field-версия RadioGroup: value-based (`value: string | null`, `onChange(value)`), рендерит\\n`options`. Привязка через {@link valueChangeAdapter} (`value` / `onValueChange`, string).\\nНЕ inline-label — подпись группы рисует FormField сверху. Экспортируется как алиас `RadioGroupField`.","params":[],"examplesCount":0,"sourcePath":"src/components/radio-group/variants/base/radio-group-base.field.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit"},{"name":"radioGroupBasePropsSchema","kind":"const","signature":"export const radioGroupBasePropsSchema","summary":"Props-схема RadioGroup — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема RadioGroup — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки. `x-registryName:\\n\'RadioGroup\'` — на этот вариант смотрит алиас `RadioGroupField`.\\n\\n`value`/`onChange` переопределяют seam под string-контракт группы (выбранное `option.value`).","params":[],"examplesCount":0,"sourcePath":"src/components/radio-group/variants/base/radio-group-base.props.ts","entries":[".","./meta","./radio-group"],"package":"@reformer/ui-kit"},{"name":"RadioGroupField","kind":"const","signature":"export const RadioGroupBaseField","summary":"Field-версия RadioGroup: value-based (`value: string | null`, `onChange(value)`), рендерит `options`.","description":"Field-версия RadioGroup: value-based (`value: string | null`, `onChange(value)`), рендерит\\n`options`. Привязка через {@link valueChangeAdapter} (`value` / `onValueChange`, string).\\nНЕ inline-label — подпись группы рисует FormField сверху. Экспортируется как алиас `RadioGroupField`.","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields"],"sourcePath":"src/components/radio-group/variants/base/radio-group-base.field.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit","usage":12},{"name":"RadioGroupItem","kind":"function","signature":"function RadioGroupItem({\\n className,\\n ...props\\n}: React.ComponentProps<typeof RadioGroupPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/radio-group/variants/base/radio-group-base.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit"},{"name":"RadioGroupOptions","kind":"function","signature":"function RadioGroupOptions({\\n options = [],\\n \'data-testid\': dataTestId,\\n ...props\\n}: RadioGroupOptionsProps)","summary":"Презентационная обёртка над base RadioGroup/RadioGroupItem: рендерит опции из массива `options`.","description":"Презентационная обёртка над base RadioGroup/RadioGroupItem: рендерит опции из массива\\n`options`. Контракт `value` / `onValueChange` совпадает с Radix Root — поэтому field-версия\\n= `withFormControl(RadioGroupOptions, valueChangeAdapter)` (без ручного маппинга событий).\\n\\nКонтейнер — `role=\\"radiogroup\\"` (Radix Root). Каждый Item получает per-option\\n`data-testid = <data-testid>-<value>`: FormField передаёт контролу `data-testid=\\"input-<field>\\"`,\\nпоэтому в форме выходит `input-<field>-<value>` (POM ждёт именно этот идентификатор). `id` Item\\nсвязывает `<label htmlFor>`, чтобы клик по подписи выбирал вариант.","params":[],"examplesCount":0,"sourcePath":"src/components/radio-group/variants/base/radio-group-base.field.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit"},{"name":"RadioGroupOptionsProps","kind":"interface","signature":"export interface RadioGroupOptionsProps extends Omit<\\n React.ComponentProps<typeof RadioGroup>,\\n \'children\'\\n> {\\n /** Список вариантов. Каждый рендерится как `RadioGroupItem` + связанная `<label>`. */\\n options?: RadioOption[];\\n /** Префикс `data-testid`; на контейнер + `-<value>` на каждый Item. */\\n \'data-testid\'?: string;\\n}","summary":"Props презентационной обёртки {@link RadioGroupOptions}.","description":"Props презентационной обёртки {@link RadioGroupOptions}.","params":[],"examplesCount":0,"sourcePath":"src/components/radio-group/variants/base/radio-group-base.field.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit"},{"name":"RadioOption","kind":"interface","signature":"export interface RadioOption {\\n /** Значение, попадающее в `onChange`. DOM `value` всегда строка. */\\n value: string;\\n /** Подпись, отображаемая справа от radio. */\\n label: string;\\n}","summary":"Один вариант выбора для {@link RadioGroupField}.","description":"Один вариант выбора для {@link RadioGroupField}.","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/radio-group/variants/base/radio-group-base.field.tsx","entries":[".","./radio-group"],"package":"@reformer/ui-kit"},{"name":"rangeIds","kind":"function","signature":"export function rangeIds(rows: readonly TreeRow[], from: string, to: string): readonly string[]","summary":"Адреса строк между двумя, включая обе, — то, что отмечает щелчок с Shift.","description":"Адреса строк между двумя, включая обе, — то, что отмечает щелчок с Shift.\\n\\nСчитается по ВИДИМЫМ строкам, а не по дереву: человек выделяет то, что видит, и строки\\nсвёрнутой ветки в диапазон попадать не должны, хотя в дереве они между ними лежат.\\nНеизвестная граница даёт пустой диапазон — выделять нечего, а не «выделить всё».","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"resizableBasePropsSchema","kind":"const","signature":"export const resizableBasePropsSchema","summary":"Props-схема Resizable (react-resizable-panels ResizablePanelGroup — экспорт не «Resizable»).","description":"Props-схема Resizable (react-resizable-panels ResizablePanelGroup — экспорт не «Resizable»).","params":[],"examplesCount":0,"sourcePath":"src/components/resizable/variants/base/resizable-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ResizableHandle","kind":"function","signature":"function ResizableHandle({\\n withHandle,\\n className,\\n ...props\\n}: ResizablePrimitive.SeparatorProps & {\\n withHandle?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/resizable/variants/base/resizable-base.tsx","entries":["./resizable"],"package":"@reformer/ui-kit"},{"name":"ResizablePanel","kind":"function","signature":"function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/resizable/variants/base/resizable-base.tsx","entries":["./resizable"],"package":"@reformer/ui-kit"},{"name":"ResizablePanelGroup","kind":"function","signature":"function ResizablePanelGroup({ className, ...props }: ResizablePrimitive.GroupProps)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/resizable/variants/base/resizable-base.tsx","entries":["./resizable"],"package":"@reformer/ui-kit"},{"name":"ResourceConfig","kind":"interface","signature":"export interface ResourceConfig<T> {\\n /** Стратегия загрузки. По умолчанию (если не задана) трактуется как `\'static\'`. */\\n type: ResourceStrategy;\\n /** Функция загрузки опций. Должна вернуть `{ items, totalCount }`. */\\n load: (params?: ResourceLoadParams) => Promise<ResourceResult<T>>;\\n /** Размер страницы для стратегии `partial`. По умолчанию 20. */\\n pageSize?: number;\\n}","summary":"Конфигурация асинхронного источника опций для {@link Select}.","description":"Конфигурация асинхронного источника опций для {@link Select}.","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"ResourceItem","kind":"interface","signature":"export interface ResourceItem<T> {\\n /** Уникальный ключ элемента (для React `key` и дедупликации страниц). */\\n id: string | number;\\n /** Видимая подпись опции. */\\n label: string;\\n /** Значение, которое попадает в `onChange` (всегда приводится к строке). */\\n value: T;\\n /** Опциональное имя группы — варианты с одинаковым `group` объединяются в `SelectGroup`. */\\n group?: string;\\n /** Дополнительные поля бек-данных. */\\n [key: string]: unknown;\\n}","summary":"Один элемент, возвращаемый {@link ResourceConfig.load}.","description":"Один элемент, возвращаемый {@link ResourceConfig.load}.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"ResourceLoadParams","kind":"interface","signature":"export interface ResourceLoadParams {\\n /** Поисковый запрос (серверная фильтрация в стратегии `partial`). */\\n search?: string;\\n /** Номер страницы (1-based) для пагинации. */\\n page?: number;\\n /** Размер страницы. */\\n pageSize?: number;\\n /** Дополнительные пользовательские параметры. */\\n [key: string]: unknown;\\n}","summary":"Параметры запроса к {@link ResourceConfig.load}.","description":"Параметры запроса к {@link ResourceConfig.load}.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"ResourceResult","kind":"interface","signature":"export interface ResourceResult<T> {\\n /** Список вариантов текущей страницы. */\\n items: ResourceItem<T>[];\\n /** Общее число доступных вариантов (для пагинации). */\\n totalCount: number;\\n}","summary":"Ответ {@link ResourceConfig.load}.","description":"Ответ {@link ResourceConfig.load}.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"ResourceStrategy","kind":"type","signature":"export type ResourceStrategy = \'static\' | \'preload\' | \'partial\';","summary":"Стратегия загрузки опций {@link Select}: - `\'static\'` — один `load({})` при монтировании; без поиска и пагинации (снимок); - `\'preload\'` — один `load({})` (сервер возвращает всё), поиск фильтрует загруженные опции на клиенте; пагинации нет; - `\'partial\'` — серверные поиск и пагинация: `load({ search","description":"Стратегия загрузки опций {@link Select}:\\n- `\'static\'` — один `load({})` при монтировании; без поиска и пагинации (снимок);\\n- `\'preload\'` — один `load({})` (сервер возвращает всё), поиск фильтрует\\n загруженные опции на клиенте; пагинации нет;\\n- `\'partial\'` — серверные поиск и пагинация: `load({ search, page })`,\\n догрузка следующих страниц при скролле до `totalCount`.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-resource.ts","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"rowRange","kind":"function","signature":"export function rowRange(\\n scrollTop: number,\\n viewportHeight: number,\\n rowHeight: number,\\n count: number,\\n overscan: number\\n): RowRange","summary":"Какие строки показать при такой прокрутке.","description":"Какие строки показать при такой прокрутке.\\n\\n`overscan` — запас строк за краями видимой области: без него строка, появляющаяся из-за\\nкрая, успевает мигнуть пустотой на быстрой прокрутке.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/use-virtual-rows.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"RowRange","kind":"interface","signature":"export interface RowRange {\\n readonly start: number;\\n readonly end: number;\\n}","summary":"Окно строк, которые нужно отрисовать: `[start, end)`.","description":"Окно строк, которые нужно отрисовать: `[start, end)`.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/use-virtual-rows.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"RuntimePropDoc","kind":"interface","signature":"export interface RuntimePropDoc extends PropDoc {\\n description: string;\\n default?: string | number | boolean;\\n}","summary":"Проп, которого НЕ бывает в `componentProps`: резолвит seam (`value`/`onChange`/`onBlur`/`disabled`) либо не представим в JSON (`resource.load`).","description":"Проп, которого НЕ бывает в `componentProps`: резолвит seam (`value`/`onChange`/`onBlur`/`disabled`)\\nлибо не представим в JSON (`resource.load`). Держим отдельно от `properties`, чтобы схема\\nне врала, будто его можно указать. Валидатор DSL этот блок не видит (вырезается с `x-*`).","params":[],"examplesCount":0,"sourcePath":"src/fields/props-schema.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ScrollArea","kind":"function","signature":"function ScrollArea({\\n className,\\n children,\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Root> & {\\n /** Толщина полос прокрутки: `xs` — тонкие (6px) для плотных рядов вроде вкладок. */\\n size?: ScrollAreaSize;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/scroll-area/variants/base/scroll-area-base.tsx","entries":[".","./scroll-area"],"package":"@reformer/ui-kit"},{"name":"scrollAreaBasePropsSchema","kind":"const","signature":"export const scrollAreaBasePropsSchema","summary":"Props-схема ScrollArea (Radix ScrollArea.Root) — кастомные скроллбары над контентом.","description":"Props-схема ScrollArea (Radix ScrollArea.Root) — кастомные скроллбары над контентом.","params":[],"examplesCount":0,"sourcePath":"src/components/scroll-area/variants/base/scroll-area-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"ScrollAreaSize","kind":"type","signature":"type ScrollAreaSize = \'default\' | \'xs\';","summary":"Ступени толщины полос прокрутки: `default` — 10px апстрима, `xs` — 6px для плотных рядов.","description":"Ступени толщины полос прокрутки: `default` — 10px апстрима, `xs` — 6px для плотных рядов.","params":[],"examplesCount":0,"sourcePath":"src/components/scroll-area/variants/base/scroll-area-base.tsx","entries":[".","./scroll-area"],"package":"@reformer/ui-kit"},{"name":"ScrollBar","kind":"function","signature":"function ScrollBar({\\n className,\\n orientation = \'vertical\',\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar> & {\\n /** Толщина полосы: `xs` — тонкая (6px) для плотных рядов вроде вкладок. */\\n size?: ScrollAreaSize;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/scroll-area/variants/base/scroll-area-base.tsx","entries":[".","./scroll-area"],"package":"@reformer/ui-kit"},{"name":"Section","kind":"function","signature":"export function Section({\\n title,\\n titleAs: TitleTag = \'h3\',\\n className,\\n titleClassName,\\n children,\\n}: SectionProps): ReactNode","summary":"Section - секция формы с заголовком.","description":"Section - секция формы с заголовком.\\n\\nСемантический `<section>`-контейнер для группировки связанных полей\\nс опциональным заголовком (`titleAs` управляет уровнем `h1`-`h6`).","params":[],"example":"Заголовок h2 + сетка из двух колонок (M1: лист = `value` + `component`)\\n```typescript\\nimport { Section, Input } from \'@reformer/ui-kit\';\\n\\n{\\ncomponent: Section,\\ncomponentProps: {\\ntitle: \'Личные данные\',\\ntitleAs: \'h2\',\\ntitleClassName: \'text-xl font-bold\',\\nclassName: \'grid grid-cols-2 gap-4\',\\n},\\nchildren: [\\n{ value: model.$.firstName, component: InputField },\\n{ value: model.$.lastName, component: InputField },\\n],\\n}\\n```","examplesCount":2,"topics":["overview","form-field-integration","form-array-section","form-layout"],"sourcePath":"src/components/section/variants/base/section-base.tsx","entries":[".","./section"],"package":"@reformer/ui-kit","usage":36},{"name":"sectionBasePropsSchema","kind":"const","signature":"export const sectionBasePropsSchema","summary":"Props-схема Section — единый источник `props[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Section — единый источник `props[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Section — DSL-контейнер (не form-control): у него нет\\nseam (`value`/`onChange`/`onBlur`/`disabled`), поэтому нет `x-runtimeProps` и field-версии.\\nРеальная поверхность в DSL — 4 сериализуемых ключа; `children` — не `componentProps`, а\\nотдельный массив дочерних нод листа (валидатор его не касается).\\n\\n`additionalProperties: false` ловит опечатки (`titel` вместо `title`).\\n`x-registryName: \'Section\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/section/variants/base/section-base.props.ts","entries":[".","./meta","./section"],"package":"@reformer/ui-kit"},{"name":"SectionProps","kind":"interface","signature":"export interface SectionProps {\\n /** Заголовок секции */\\n title?: string;\\n /** HTML элемент для заголовка (h1-h6). По умолчанию h3 */\\n titleAs?: \'h1\' | \'h2\' | \'h3\' | \'h4\' | \'h5\' | \'h6\';\\n /** CSS класс для контейнера */\\n className?: string;\\n /** CSS класс для заголовка */\\n titleClassName?: string;\\n /** Дочерние элементы */\\n children?: ReactNode;\\n}","summary":"Props компонента Section","description":"Props компонента Section","params":[],"examplesCount":0,"sourcePath":"src/components/section/variants/base/section-base.tsx","entries":[".","./section"],"package":"@reformer/ui-kit"},{"name":"Select","kind":"function","signature":"function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields","form-field-integration","troubleshooting","form-array-section","imperative-handles"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit","usage":5},{"name":"SelectAsync","kind":"const","signature":"const SelectAsync","summary":"Высокоуровневый Select (вариант `async`): inline `options` ИЛИ асинхронный `resource` (`static` / `preload` / `partial`) с поиском, пагинацией и очисткой.","description":"Высокоуровневый Select (вариант `async`): inline `options` ИЛИ асинхронный `resource`\\n(`static` / `preload` / `partial`) с поиском, пагинацией и очисткой. Value-based контракт\\n(`value` / `onChange(string|null)` / `onBlur`) — пригоден для формы напрямую (см. `SelectAsyncField`).","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-async.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectAsyncField","kind":"const","signature":"export const SelectAsyncField","summary":"`exposesHandle: true` — SelectAsync сам реализует {@link SelectAsyncHandle} (useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — SelectAsync сам реализует {@link SelectAsyncHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/select/variants/async/select-async.field.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectAsyncHandle","kind":"interface","signature":"export interface SelectAsyncHandle extends FieldHandle {\\n /** Открыть дропдаун. */\\n open(): void;\\n /** Закрыть дропдаун (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить выбранное значение в `null`. */\\n clear(): void;\\n /** Перезагрузить источник опций с первой страницы. */\\n reload(): void;\\n /** Догрузить следующую страницу (стратегия `partial`). */\\n loadMore(): void;\\n}","summary":"Императивный handle {@link SelectAsync}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/ getElement на кнопке-триггере) + управление дропдауном и асинхронным источником.","description":"Императивный handle {@link SelectAsync}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/\\ngetElement на кнопке-триггере) + управление дропдауном и асинхронным источником. Достаётся из схемы:\\n`schema.node(\'city\').getRef<SelectAsyncHandle>().current?.reload()`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/components/select/variants/async/select-async.tsx","entries":[".","./select"],"package":"@reformer/ui-kit","usage":4},{"name":"SelectAsyncProps","kind":"interface","signature":"export interface SelectAsyncProps extends Omit<\\n React.ComponentProps<typeof SelectPrimitive.Root>,\\n \'value\' | \'onValueChange\'\\n> {\\n className?: string;\\n /** Выбранное значение (строка из `option.value`). `null` — ничего не выбрано. */\\n value?: string | null;\\n /** Обработчик выбора. При нажатии на крестик (`clearable`) приходит `null`. */\\n onChange?: (value: string | null) => void;\\n /** Срабатывает при закрытии дропдауна (через `onOpenChange(false)`). */\\n onBlur?: () => void;\\n /** Асинхронный источник опций. Если задан вместе с `options`, приоритет у `options`. */\\n resource?: ResourceConfig<unknown>;\\n /** Inline-варианты. Опции с одинаковым `group` объединяются в `SelectGroup` с `SelectLabel`. */\\n options?: Array<{ value: string | number; label: string; group?: string }>;\\n /** Подсказка в триггере. По умолчанию `\'Select an option...\'`. */\\n placeholder?: string;\\n disabled?: boolean;\\n /** Показывать ли кнопку очистки (X) справа от значения. По умолчанию `false`. */\\n clearable?: boolean;\\n}","summary":"Props компонента {@link SelectAsync}.","description":"Props компонента {@link SelectAsync}.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-async.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"selectAsyncPropsSchema","kind":"const","signature":"export const selectAsyncPropsSchema","summary":"Props-схема варианта `select/async` — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема варианта `select/async` — единый источник `api.controls[]` (reformer-doc) и\\nDSL-валидации `componentProps` (renderer-json). Реальная поверхность в DSL — 4 ключа;\\n`additionalProperties: false` ловит опечатки (`lable` вместо `label` подмешивается враппером).\\n\\n`x-registryName: \'Select\'` — на этот вариант смотрит алиас `SelectField`.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/async/select-async.props.ts","entries":[".","./meta","./select"],"package":"@reformer/ui-kit"},{"name":"SelectContent","kind":"function","signature":"function SelectContent({\\n className,\\n children,\\n position = \'item-aligned\',\\n align = \'center\',\\n header,\\n onViewportScroll,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.Content> & {\\n /** ReFormer-расширение: нескроллящаяся шапка над списком (например, поле поиска). */\\n header?: React.ReactNode;\\n /** ReFormer-расширение: обработчик прокрутки viewport-а со списком (для infinite-scroll). */\\n onViewportScroll?: React.UIEventHandler<HTMLDivElement>;\\n})","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectField","kind":"const","signature":"export const SelectAsyncField","summary":"`exposesHandle: true` — SelectAsync сам реализует {@link SelectAsyncHandle} (useImperativeHandle), поэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","description":"`exposesHandle: true` — SelectAsync сам реализует {@link SelectAsyncHandle} (useImperativeHandle),\\nпоэтому HOC форвардит ref потребителя прямо в композит (passthrough), без своего baseline-handle.","params":[],"examplesCount":0,"topics":["overview","choice-fields","form-field-integration","form-array-section","imperative-handles"],"sourcePath":"src/components/select/variants/async/select-async.field.tsx","entries":[".","./select"],"package":"@reformer/ui-kit","usage":23},{"name":"SelectGroup","kind":"function","signature":"function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectItem","kind":"function","signature":"function SelectItem({\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.Item>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectLabel","kind":"function","signature":"function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectMulti","kind":"const","signature":"const SelectMulti","summary":"Select в режиме множественного выбора (вариант `multi`).","description":"Select в режиме множественного выбора (вариант `multi`).\\n\\nRadix Select мультивыбора не поддерживает в принципе: его `Root` типизирован строго под одно\\nзначение, `SelectValue` рисует одно, а `SelectItem` даёт `role=option` в listbox без\\n`aria-multiselectable`. Поэтому вариант НЕ переиспользует `select-base.tsx`, а строится на\\n`Popover` со своим listbox.\\n\\nНа cmdk (как `ComboboxMulti`) он тоже построен быть не может, и это ограничение упаковки, а не\\nвкуса: каталоги `command` и `combobox` лежат в HEAVY и держат cmdk опциональным peer\'ом, а\\n`select` — лёгкий и попадает в главный barrel. Импорт `Command` сюда протащил бы cmdk в\\n`dist/index.js` и сделал бы его обязательным для КАЖДОГО потребителя barrel\'а. Отсюда свой\\nlistbox и своё поле поиска — ровно такое же, как уже есть в `select-async.tsx`.\\n\\nСтратегии источника, поиск и пагинация переиспользуются из соседнего варианта без изменений\\n(`use-resource-options.ts` поверх чистого редьюсера `select-resource.ts`).","params":[],"examplesCount":0,"topics":["choice-fields","troubleshooting"],"sourcePath":"src/components/select/variants/multi/select-multi.tsx","entries":[".","./select"],"package":"@reformer/ui-kit","usage":1},{"name":"SelectMultiField","kind":"const","signature":"export const SelectMultiField","summary":"`exposesHandle: true` — SelectMulti сам реализует {@link SelectMultiHandle} (`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough).","description":"`exposesHandle: true` — SelectMulti сам реализует {@link SelectMultiHandle}\\n(`useImperativeHandle`), поэтому HOC форвардит ref потребителя прямо в композит (passthrough).\\nПривязка — общий для кита {@link multiValueAdapter}.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/select/variants/multi/select-multi.field.tsx","entries":[".","./select"],"package":"@reformer/ui-kit","usage":2},{"name":"SelectMultiFieldProps","kind":"interface","signature":"export interface SelectMultiFieldProps {\\n value?: string[] | null;\\n onChange?: (value: string[] | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n options?: SelectMultiOption[];\\n selectedOptions?: SelectMultiOption[];\\n resource?: ResourceConfig<unknown>;\\n placeholder?: string;\\n searchPlaceholder?: string;\\n emptyText?: string;\\n clearable?: boolean;\\n maxItems?: number;\\n summaryThreshold?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии SelectMulti.","description":"Value-based контракт field-версии SelectMulti. Значение — `string[] | null`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт остальное в `componentProps`\\n(кроме `resource` — он требует функцию и передаётся через реестр компонентов).\\nСлужит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/multi/select-multi.field.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectMultiHandle","kind":"interface","signature":"export interface SelectMultiHandle extends FieldHandle {\\n /** Открыть popover со списком. */\\n open(): void;\\n /** Закрыть popover (эмитит `onBlur`, как обычное закрытие). */\\n close(): void;\\n /** Сбросить весь выбор. */\\n clear(): void;\\n /** Перезагрузить источник опций с первой страницы. */\\n reload(): void;\\n /** Догрузить следующую страницу (стратегия `partial`). */\\n loadMore(): void;\\n}","summary":"Императивный handle {@link SelectMulti}: baseline {@link FieldHandle} на кнопке-триггере + управление popover\'ом и асинхронным источником.","description":"Императивный handle {@link SelectMulti}: baseline {@link FieldHandle} на кнопке-триггере +\\nуправление popover\'ом и асинхронным источником.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/multi/select-multi.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectMultiOption","kind":"interface","signature":"export interface SelectMultiOption {\\n value: string;\\n label: string;\\n group?: string;\\n}","summary":"Опция мультивыбора, заданная inline (сериализуемый источник для формы/DSL).","description":"Опция мультивыбора, заданная inline (сериализуемый источник для формы/DSL).","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/multi/select-multi.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectMultiProps","kind":"interface","signature":"export interface SelectMultiProps {\\n className?: string;\\n /**\\n * Выбранные значения. Приходит массивом всегда: `multiValueAdapter` разворачивает `null` в `[]`.\\n */\\n value?: string[];\\n /** Изменение выбора. Всегда получает НОВЫЙ массив — см. `multiValueAdapter`. */\\n onChange?: (value: string[]) => void;\\n /** Срабатывает при закрытии popover (снятие фокуса). */\\n onBlur?: () => void;\\n /** Inline-опции. Взаимоисключающи с `resource`: если заданы — источник не опрашивается. */\\n options?: SelectMultiOption[];\\n /**\\n * Асинхронный источник опций (`static` / `preload` / `partial`). В JSON-форме недостижим:\\n * требует функцию `load` — передаётся через реестр компонентов.\\n */\\n resource?: ResourceConfig<unknown>;\\n /**\\n * Лейблы для уже выбранных значений, которых может не быть в текущей странице опций.\\n *\\n * Нужен именно при `resource`: выбранное значение легко оказывается вне загруженной страницы\\n * (сменили поисковый запрос, перезагрузили источник, выбрали на первой странице и пролистали\\n * дальше). Без справочника чип показывал бы сырой `value`. Сериализуем — доступен и из JSON-DSL.\\n */\\n selectedOptions?: SelectMultiOption[];\\n /** Подсказка в триггере, пока ничего не выбрано. */\\n placeholder?: string;\\n /** Подсказка в поле поиска. */\\n searchPlaceholder?: string;\\n /** Текст пустого состояния (ничего не найдено). */\\n emptyText?: string;\\n /** Показывать крестик сброса ВСЕГО выбора. */\\n clearable?: boolean;\\n /**\\n * Потолок числа выбранных: по достижении невыбранные пункты выключаются.\\n * Подсказка интерфейса, а НЕ правило формы — ограничение задавайте валидатором `maxLength(n)`.\\n */\\n maxItems?: number;\\n /** Сколько чипов показать в триггере до схлопывания в сводку. По умолчанию 3. */\\n summaryThreshold?: number;\\n disabled?: boolean;\\n /** id корневого элемента — по нему форма связывает подпись, описание и сообщение об ошибке. */\\n id?: string;\\n /** Префикс `data-testid`; на триггер + `-<value>` на каждый пункт списка. */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props компонента {@link SelectMulti}.","description":"Props компонента {@link SelectMulti}.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/multi/select-multi.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"selectMultiPropsSchema","kind":"const","signature":"export const selectMultiPropsSchema","summary":"Props-схема SelectMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема SelectMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'SelectMulti\'` — отдельная запись каталога, а не проп у `Select`: тип значения\\nдругой (`string[] | null` против `string | null`), а `x-runtimeProps.value` у записи ровно один.\\nПрецедент — `FileUpload` / `FileUploadAvatar`.\\n\\nОтдельной записи `SelectAsyncMulti` НЕ существует и существовать не может: `Select` и\\n`SelectAsync` — одна запись каталога (`x-registryName: \'Select\'` стоит на `select-async.props.ts`,\\nа `SelectField` — алиас `SelectAsyncField`). Асинхронный источник, поиск и пагинация здесь —\\nэто ПРОПСЫ (`resource`), а не отдельный вариант.","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/multi/select-multi.props.ts","entries":[".","./meta","./select"],"package":"@reformer/ui-kit"},{"name":"SelectScrollDownButton","kind":"function","signature":"function SelectScrollDownButton({\\n className,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>)","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectScrollUpButton","kind":"function","signature":"function SelectScrollUpButton({\\n className,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>)","summary":"","params":[],"examplesCount":0,"topics":["choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectSeparator","kind":"function","signature":"function SelectSeparator({\\n className,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectTrigger","kind":"function","signature":"function SelectTrigger({\\n className,\\n size = \'default\',\\n children,\\n ...props\\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\\n size?: \'sm\' | \'default\';\\n})","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"SelectValue","kind":"function","signature":"function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>)","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/select/variants/base/select-base.tsx","entries":[".","./select"],"package":"@reformer/ui-kit"},{"name":"Separator","kind":"function","signature":"function Separator({\\n className,\\n orientation = \'horizontal\',\\n decorative = true,\\n ...props\\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview","form-layout"],"sourcePath":"src/components/separator/variants/base/separator-base.tsx","entries":[".","./separator"],"package":"@reformer/ui-kit"},{"name":"separatorBasePropsSchema","kind":"const","signature":"export const separatorBasePropsSchema","summary":"Props-схема презентационного `Separator` — единый источник api/props (reformer-doc) и валидации `componentProps` (renderer-json).","description":"Props-схема презентационного `Separator` — единый источник api/props (reformer-doc) и\\nвалидации `componentProps` (renderer-json). `Separator` — обёртка над Radix `Separator.Root`\\n(не form-control), поэтому в схеме нет `x-runtimeProps`.\\n\\n`additionalProperties: false` ловит опечатки в DSL.\\n`x-registryName: \'Separator\'` — каноническое имя в реестре renderer-json.","params":[],"examplesCount":0,"sourcePath":"src/components/separator/variants/base/separator-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"Sheet","kind":"function","signature":"function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"sheetBasePropsSchema","kind":"const","signature":"export const sheetBasePropsSchema","summary":"Props-схема Sheet (Radix Dialog.Root) — провайдер без DOM (className/side — на SheetContent).","description":"Props-схема Sheet (Radix Dialog.Root) — провайдер без DOM (className/side — на SheetContent).","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"SheetClose","kind":"function","signature":"function SheetClose({ ...props }: React.ComponentProps<typeof SheetPrimitive.Close>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetContent","kind":"function","signature":"function SheetContent({\\n className,\\n children,\\n side = \'right\',\\n showCloseButton = true,\\n ...props\\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\\n side?: \'top\' | \'right\' | \'bottom\' | \'left\';\\n showCloseButton?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetDescription","kind":"function","signature":"function SheetDescription({\\n className,\\n ...props\\n}: React.ComponentProps<typeof SheetPrimitive.Description>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetFooter","kind":"function","signature":"function SheetFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetHeader","kind":"function","signature":"function SheetHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetOverlay","kind":"function","signature":"function SheetOverlay({\\n className,\\n ...props\\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetPortal","kind":"function","signature":"function SheetPortal({ ...props }: React.ComponentProps<typeof SheetPrimitive.Portal>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetTitle","kind":"function","signature":"function SheetTitle({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Title>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"SheetTrigger","kind":"function","signature":"function SheetTrigger({ ...props }: React.ComponentProps<typeof SheetPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sheet/variants/base/sheet-base.tsx","entries":[".","./sheet"],"package":"@reformer/ui-kit"},{"name":"Sidebar","kind":"function","signature":"function Sidebar({\\n side = \'left\',\\n variant = \'sidebar\',\\n collapsible = \'offcanvas\',\\n className,\\n children,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n side?: \'left\' | \'right\';\\n variant?: \'sidebar\' | \'floating\' | \'inset\';\\n collapsible?: \'offcanvas\' | \'icon\' | \'none\';\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"sidebarBasePropsSchema","kind":"const","signature":"export const sidebarBasePropsSchema","summary":"Props-схема Sidebar (лейаут-компонент).","description":"Props-схема Sidebar (лейаут-компонент). Требует SidebarProvider-контекст в рантайме; в превью —\\nзаглушка. Управление open/onOpenChange — на провайдере (runtime), не в схеме.","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"SidebarContent","kind":"function","signature":"function SidebarContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarFooter","kind":"function","signature":"function SidebarFooter({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarGroup","kind":"function","signature":"function SidebarGroup({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarGroupAction","kind":"function","signature":"function SidebarGroupAction({\\n className,\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'button\'> & { asChild?: boolean })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarGroupContent","kind":"function","signature":"function SidebarGroupContent({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarGroupLabel","kind":"function","signature":"function SidebarGroupLabel({\\n className,\\n asChild = false,\\n ...props\\n}: React.ComponentProps<\'div\'> & { asChild?: boolean })","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarHeader","kind":"function","signature":"function SidebarHeader({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarInput","kind":"function","signature":"function SidebarInput({ className, ...props }: React.ComponentProps<typeof Input>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarInset","kind":"function","signature":"function SidebarInset({ className, ...props }: React.ComponentProps<\'main\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenu","kind":"function","signature":"function SidebarMenu({ className, ...props }: React.ComponentProps<\'ul\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuAction","kind":"function","signature":"function SidebarMenuAction({\\n className,\\n asChild = false,\\n showOnHover = false,\\n ...props\\n}: React.ComponentProps<\'button\'> & {\\n asChild?: boolean;\\n showOnHover?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuBadge","kind":"function","signature":"function SidebarMenuBadge({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuButton","kind":"function","signature":"function SidebarMenuButton({\\n asChild = false,\\n isActive = false,\\n variant = \'default\',\\n size = \'default\',\\n tooltip,\\n className,\\n ...props\\n}: React.ComponentProps<\'button\'> & {\\n asChild?: boolean;\\n isActive?: boolean;\\n tooltip?: string | React.ComponentProps<typeof TooltipContent>;\\n} & VariantProps<typeof sidebarMenuButtonVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuItem","kind":"function","signature":"function SidebarMenuItem({ className, ...props }: React.ComponentProps<\'li\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuSkeleton","kind":"function","signature":"function SidebarMenuSkeleton({\\n className,\\n showIcon = false,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n showIcon?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuSub","kind":"function","signature":"function SidebarMenuSub({ className, ...props }: React.ComponentProps<\'ul\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuSubButton","kind":"function","signature":"function SidebarMenuSubButton({\\n asChild = false,\\n size = \'md\',\\n isActive = false,\\n className,\\n ...props\\n}: React.ComponentProps<\'a\'> & {\\n asChild?: boolean;\\n size?: \'sm\' | \'md\';\\n isActive?: boolean;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarMenuSubItem","kind":"function","signature":"function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<\'li\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarProvider","kind":"function","signature":"function SidebarProvider({\\n defaultOpen = true,\\n open: openProp,\\n onOpenChange: setOpenProp,\\n className,\\n style,\\n children,\\n ...props\\n}: React.ComponentProps<\'div\'> & {\\n defaultOpen?: boolean;\\n open?: boolean;\\n onOpenChange?: (open: boolean) => void;\\n})","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarRail","kind":"function","signature":"function SidebarRail({ className, ...props }: React.ComponentProps<\'button\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarSeparator","kind":"function","signature":"function SidebarSeparator({ className, ...props }: React.ComponentProps<typeof Separator>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"SidebarTrigger","kind":"function","signature":"function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<typeof Button>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"Skeleton","kind":"function","signature":"function Skeleton({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/skeleton/variants/base/skeleton-base.tsx","entries":[".","./skeleton"],"package":"@reformer/ui-kit"},{"name":"skeletonBasePropsSchema","kind":"const","signature":"export const skeletonBasePropsSchema","summary":"Props-схема Skeleton — плейсхолдер загрузки (div).","description":"Props-схема Skeleton — плейсхолдер загрузки (div). Единственный сериализуемый проп — className.","params":[],"examplesCount":0,"sourcePath":"src/components/skeleton/variants/base/skeleton-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"Slider","kind":"function","signature":"function Slider({\\n className,\\n defaultValue,\\n value,\\n min = 0,\\n max = 100,\\n ...props\\n}: React.ComponentProps<typeof SliderPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/slider/variants/base/slider-base.tsx","entries":[".","./slider"],"package":"@reformer/ui-kit"},{"name":"sliderAdapter","kind":"const","signature":"export const sliderAdapter: FieldAdapter","summary":"Slider — `value: number[]` + `onValueChange(number[])`.","description":"Slider — `value: number[]` + `onValueChange(number[])`. Одно-thumb режим: берём первый.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"SliderBaseField","kind":"const","signature":"export const SliderBaseField","summary":"Field-версия Slider: pure shadcn Slider + `sliderAdapter`.","description":"Field-версия Slider: pure shadcn Slider + `sliderAdapter`. Скалярный контракт формы\\n(`value: number | null`) сводится к Radix-массиву: `toValue: v => [v ?? 0]` (одно-thumb),\\n`fromEmit: arr => arr[0] ?? null`. НЕ inline-раскладка — верхнюю подпись рисует FormField\\n(маркер `reformerLayout` не ставится). Экспортируется как алиас `SliderField`.","params":[],"examplesCount":0,"sourcePath":"src/components/slider/variants/base/slider-base.field.tsx","entries":[".","./slider"],"package":"@reformer/ui-kit"},{"name":"sliderBasePropsSchema","kind":"const","signature":"export const sliderBasePropsSchema","summary":"Props-схема Slider — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Slider — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Поверхность в DSL — `min`/`max`/`step` (диапазон Radix)\\n+ `className`; `additionalProperties: false` ловит опечатки. `x-registryName: \'Slider\'` —\\nна этот вариант смотрит алиас `SliderField`.\\n\\n`value`/`onChange` скалярны (`number | null`): base — Radix `value: number[]` /\\n`onValueChange(number[])`, но `sliderAdapter` сводит одно-thumb режим к числу.","params":[],"examplesCount":0,"sourcePath":"src/components/slider/variants/base/slider-base.props.ts","entries":[".","./meta","./slider"],"package":"@reformer/ui-kit"},{"name":"SliderField","kind":"const","signature":"export const SliderBaseField","summary":"Field-версия Slider: pure shadcn Slider + `sliderAdapter`.","description":"Field-версия Slider: pure shadcn Slider + `sliderAdapter`. Скалярный контракт формы\\n(`value: number | null`) сводится к Radix-массиву: `toValue: v => [v ?? 0]` (одно-thumb),\\n`fromEmit: arr => arr[0] ?? null`. НЕ inline-раскладка — верхнюю подпись рисует FormField\\n(маркер `reformerLayout` не ставится). Экспортируется как алиас `SliderField`.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/slider/variants/base/slider-base.field.tsx","entries":[".","./slider"],"package":"@reformer/ui-kit"},{"name":"SliderFieldProps","kind":"interface","signature":"export interface SliderFieldProps {\\n value?: number | null;\\n onChange?: (value: number | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n min?: number;\\n max?: number;\\n step?: number;\\n className?: string;\\n}","summary":"Value-based контракт field-версии Slider.","description":"Value-based контракт field-версии Slider. Значение — `number | null`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт `min`/`max`/`step`/`className` в\\n`componentProps`. Служит типом для стража props-схемы: base — Radix `value: number[]` /\\n`onValueChange`, а field-контракт скалярный (`sliderAdapter`, одно-thumb режим).","params":[],"examplesCount":0,"sourcePath":"src/components/slider/variants/base/slider-base.field.tsx","entries":[".","./slider"],"package":"@reformer/ui-kit"},{"name":"Spinner","kind":"function","signature":"function Spinner({ className, ...props }: React.ComponentProps<\'svg\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/spinner/variants/base/spinner-base.tsx","entries":[".","./spinner"],"package":"@reformer/ui-kit"},{"name":"spinnerBasePropsSchema","kind":"const","signature":"export const spinnerBasePropsSchema","summary":"Props-схема Spinner — презентационный индикатор загрузки поверх lucide Loader2Icon.","description":"Props-схема Spinner — презентационный индикатор загрузки поверх lucide Loader2Icon.\\nСобственных сериализуемых пропсов нет: принимает только SVG-атрибуты, размер задаётся\\nчерез className (size-*). Поэтому единственный статический проп — className.","params":[],"examplesCount":0,"sourcePath":"src/components/spinner/variants/base/spinner-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"splitFileUploadProps","kind":"function","signature":"export function splitFileUploadProps(props: FileUploadBaseProps & Record<string, unknown>)","summary":"Собирает опции CDK-хука из props варианта, отделяя презентационные и DOM-rest.","description":"Собирает опции CDK-хука из props варианта, отделяя презентационные и DOM-rest.","params":[],"examplesCount":0,"sourcePath":"src/components/file-upload/variants/base/file-upload-base.tsx","entries":[".","./file-upload"],"package":"@reformer/ui-kit"},{"name":"StepIndicator","kind":"const","signature":"export const StepIndicator: FC<StepIndicatorProps>","summary":"Визуальная цепочка шагов wizard\'а — иконки, заголовки и соединительные линии с подсветкой текущего / завершённого шага.","description":"Визуальная цепочка шагов wizard\'а — иконки, заголовки и соединительные линии\\nс подсветкой текущего / завершённого шага. Клик (и Enter) по доступному шагу\\nвызывает `goToStep`; недоступные шаги приглушены и не кликабельны. Разметка\\nдоступна для скринридеров (`role=\\"navigation\\"`, `aria-current=\\"step\\"`,\\nнастраиваемые aria-метки).\\n\\nРендерится из headless-слота `<FormWizard.Indicator>` через render-prop\\n(`steps` со статусами и `goToStep` приходят автоматически). Готовый\\n{@link FormWizard} уже подключает этот компонент; напрямую нужен только для\\nкастомной раскладки.","params":[],"example":"Индикатор с кастомной aria-меткой контейнера\\n```tsx\\n<FormWizard.Indicator steps={steps}>\\n{(indicator) => (\\n<StepIndicator {...indicator} navAriaLabel=\\"Этапы заявки\\" className=\\"mb-8\\" />\\n)}\\n</FormWizard.Indicator>\\n```","examplesCount":1,"sourcePath":"src/components/form-wizard/variants/base/step-indicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"StepIndicatorProps","kind":"interface","signature":"export interface StepIndicatorProps extends FormWizardIndicatorRenderProps {\\n /** Внешний CSS-класс контейнера. */\\n className?: string;\\n /** Aria-label контейнера навигации. По умолчанию «Шаги формы». */\\n navAriaLabel?: string;\\n /** Кастомный шаблон aria-label для шага. Получает {step}. */\\n stepAriaLabel?: (step: FormWizardIndicatorStepWithState) => string;\\n}","summary":"Пропсы {@link StepIndicator}: render-props индикатора из слота `<FormWizard.Indicator>` (`steps` со статусами, `goToStep`) плюс `className` и настройка aria-меток.","description":"Пропсы {@link StepIndicator}: render-props индикатора из слота\\n`<FormWizard.Indicator>` (`steps` со статусами, `goToStep`) плюс `className`\\nи настройка aria-меток.","params":[],"examplesCount":0,"sourcePath":"src/components/form-wizard/variants/base/step-indicator.tsx","entries":[".","./form-wizard"],"package":"@reformer/ui-kit"},{"name":"Switch","kind":"function","signature":"function Switch({\\n className,\\n size = \'default\',\\n ...props\\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\\n size?: \'sm\' | \'default\';\\n})","summary":"","params":[],"examplesCount":0,"topics":["overview","form-field-integration"],"sourcePath":"src/components/switch/variants/base/switch-base.tsx","entries":[".","./switch"],"package":"@reformer/ui-kit"},{"name":"SwitchBaseField","kind":"const","signature":"export const SwitchBaseField","summary":"Field-версия Switch: обёртка `SwitchControl` (переключатель + подпись справа) + `checkedAdapter` (boolean value-based: `checked` + `onCheckedChange`, `\'indeterminate\'` → `false`).","description":"Field-версия Switch: обёртка `SwitchControl` (переключатель + подпись справа) + `checkedAdapter`\\n(boolean value-based: `checked` + `onCheckedChange`, `\'indeterminate\'` → `false`).\\n\\nМаркер `reformerLayout = \'inline-label\'` — ИНВАРИАНТ playbook (фаза D2): FormField НЕ рисует\\nверхнюю подпись (иначе задвоится с той, что контрол рендерит справа из `componentProps.label`).","params":[],"examplesCount":0,"sourcePath":"src/components/switch/variants/base/switch-base.field.tsx","entries":[".","./switch"],"package":"@reformer/ui-kit"},{"name":"switchBasePropsSchema","kind":"const","signature":"export const switchBasePropsSchema","summary":"Props-схема Switch — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Switch — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Поверхность в DSL — `label` + `className`;\\n`additionalProperties: false` ловит опечатки. `x-registryName: \'Switch\'` — алиас `SwitchField`.\\n\\nInline-раскладка: `label` рисуется САМИМ контролом справа (FormField верхнюю метку не дублирует).","params":[],"examplesCount":0,"sourcePath":"src/components/switch/variants/base/switch-base.props.ts","entries":[".","./meta","./switch"],"package":"@reformer/ui-kit"},{"name":"SwitchControlProps","kind":"interface","signature":"export interface SwitchControlProps extends React.ComponentProps<typeof Switch> {\\n /** Подпись справа от переключателя. Если опущена — рендерится только сам контрол. */\\n label?: string;\\n}","summary":"Презентационная обёртка: shadcn Switch + подпись справа (event-shape Radix: `checked`/ `onCheckedChange`).","description":"Презентационная обёртка: shadcn Switch + подпись справа (event-shape Radix: `checked`/\\n`onCheckedChange`). Подпись связывается с контролом через `htmlFor` — доступное имя даёт\\nсвязанный `<Label>`. Поэтому висячий `aria-labelledby` (FormField для inline-раскладки НЕ\\nрендерит верхнюю метку — IDREF указывал бы в пустоту) сбрасываем, когда рисуем свою подпись.","params":[],"examplesCount":0,"sourcePath":"src/components/switch/variants/base/switch-base.field.tsx","entries":[".","./switch"],"package":"@reformer/ui-kit"},{"name":"SwitchField","kind":"const","signature":"export const SwitchBaseField","summary":"Field-версия Switch: обёртка `SwitchControl` (переключатель + подпись справа) + `checkedAdapter` (boolean value-based: `checked` + `onCheckedChange`, `\'indeterminate\'` → `false`).","description":"Field-версия Switch: обёртка `SwitchControl` (переключатель + подпись справа) + `checkedAdapter`\\n(boolean value-based: `checked` + `onCheckedChange`, `\'indeterminate\'` → `false`).\\n\\nМаркер `reformerLayout = \'inline-label\'` — ИНВАРИАНТ playbook (фаза D2): FormField НЕ рисует\\nверхнюю подпись (иначе задвоится с той, что контрол рендерит справа из `componentProps.label`).","params":[],"examplesCount":0,"topics":["overview","form-field-integration"],"sourcePath":"src/components/switch/variants/base/switch-base.field.tsx","entries":[".","./switch"],"package":"@reformer/ui-kit"},{"name":"SwitchFieldProps","kind":"interface","signature":"export interface SwitchFieldProps {\\n value?: boolean;\\n onChange?: (value: boolean) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n label?: string;\\n className?: string;\\n}","summary":"Value-based контракт field-версии Switch.","description":"Value-based контракт field-версии Switch. Значение — `boolean`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт `label`/`className` в `componentProps`.\\nСлужит типом для стража props-схемы (base — Radix `checked`/`onCheckedChange`, не `value`).","params":[],"examplesCount":0,"sourcePath":"src/components/switch/variants/base/switch-base.field.tsx","entries":[".","./switch"],"package":"@reformer/ui-kit"},{"name":"Table","kind":"function","signature":"function Table({ className, ...props }: React.ComponentProps<\'table\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"tableBasePropsSchema","kind":"const","signature":"export const tableBasePropsSchema","summary":"Props-схема презентационного `Table` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Table` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Table\'` — каноническое имя в реестре renderer-json.\\nКорень `Table` — чистый `ComponentProps<\'table\'>` (дословный shadcn, без cva/Radix):\\nединственный сериализуемый проп — `className`.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TableBody","kind":"function","signature":"function TableBody({ className, ...props }: React.ComponentProps<\'tbody\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableCaption","kind":"function","signature":"function TableCaption({ className, ...props }: React.ComponentProps<\'caption\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableCell","kind":"function","signature":"function TableCell({ className, ...props }: React.ComponentProps<\'td\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableColumn","kind":"interface","signature":"export interface TableColumn<Row> {\\n /** Уникальный id колонки (ключ; попадает в `sorting[].id` и `filters`). */\\n id: string;\\n /** Заголовок колонки. */\\n header: React.ReactNode;\\n /** Извлекатель содержимого ячейки из строки. Если не задан — ячейка пустая. */\\n accessor?: (row: Row) => React.ReactNode;\\n /** Разрешить сортировку по колонке (кликабельный заголовок). По умолчанию `false`. */\\n sortable?: boolean;\\n /** Разрешить фильтрацию по колонке (текстовый инпут в тулбаре). По умолчанию `false`. */\\n filterable?: boolean;\\n /** Плейсхолдер для фильтр-инпута колонки. По умолчанию — `id`. */\\n filterPlaceholder?: string;\\n /** Горизонтальное выравнивание содержимого. По умолчанию `left`. */\\n align?: \'left\' | \'center\' | \'right\';\\n /** Доп. className для ячеек и заголовка колонки. */\\n className?: string;\\n}","summary":"Описание одной колонки DataGrid.","description":"Описание одной колонки DataGrid.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableFilters","kind":"type","signature":"export type TableFilters = Record<string, unknown>;","summary":"Плоская карта активных фильтров: id колонки → значение фильтра.","description":"Плоская карта активных фильтров: id колонки → значение фильтра.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableFooter","kind":"function","signature":"function TableFooter({ className, ...props }: React.ComponentProps<\'tfoot\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableHead","kind":"function","signature":"function TableHead({ className, ...props }: React.ComponentProps<\'th\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableHeader","kind":"function","signature":"function TableHeader({ className, ...props }: React.ComponentProps<\'thead\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TablePage","kind":"interface","signature":"export interface TablePage<Row> {\\n /** Строки текущей страницы. */\\n rows: Row[];\\n /** Общее число строк во всём наборе (для расчёта числа страниц). */\\n total: number;\\n}","summary":"Результат {@link TableSettings.dataProvider}: строки текущей страницы + общее число строк.","description":"Результат {@link TableSettings.dataProvider}: строки текущей страницы + общее число строк.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableQuery","kind":"interface","signature":"export interface TableQuery {\\n /** Активные фильтры колонок (id → значение). Пустая карта, если фильтров нет. */\\n filters: TableFilters;\\n /** Текущая страница (`pageIndex` с 0) и размер страницы. */\\n pagination: { pageIndex: number; pageSize: number };\\n /** Активная сортировка (порядок значим). `desc` — по убыванию. */\\n sorting: { id: string; desc: boolean }[];\\n}","summary":"Аргумент запроса, который DataGrid передаёт в {@link TableSettings.dataProvider}.","description":"Аргумент запроса, который DataGrid передаёт в {@link TableSettings.dataProvider}.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableRow","kind":"function","signature":"function TableRow({ className, ...props }: React.ComponentProps<\'tr\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/base/table-base.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableSelectionMode","kind":"type","signature":"export type TableSelectionMode = \'none\' | \'single\' | \'multiple\';","summary":"Режим выделения строк DataGrid.","description":"Режим выделения строк DataGrid.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"TableSettings","kind":"interface","signature":"export interface TableSettings<Row> {\\n /**\\n * Провайдер данных. Вызывается при монтировании и при любом изменении\\n * pagination / sorting / filters. Должен вернуть строки текущей страницы и общее\\n * число строк. Отклонение промиса → состояние ошибки с кнопкой «Повторить».\\n */\\n dataProvider: (query: TableQuery) => Promise<TablePage<Row>>;\\n /** Колонки таблицы. */\\n columns: TableColumn<Row>[];\\n /** Размер страницы. По умолчанию `10`. */\\n pageSize?: number;\\n /** Стабильный ключ строки (для React-key и выделения). По умолчанию — индекс. */\\n rowKey?: (row: Row) => string | number;\\n /** Режим выделения строк. По умолчанию `none`. */\\n selection?: TableSelectionMode;\\n}","summary":"Контракт настроек DataGrid.","description":"Контракт настроек DataGrid.","params":[],"examplesCount":0,"sourcePath":"src/components/table/variants/data-grid/table-data-grid.tsx","entries":["./table"],"package":"@reformer/ui-kit"},{"name":"Tabs","kind":"function","signature":"function Tabs({\\n className,\\n orientation = \'horizontal\',\\n ...props\\n}: React.ComponentProps<typeof TabsPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.tsx","entries":[".","./tabs"],"package":"@reformer/ui-kit"},{"name":"tabsBasePropsSchema","kind":"const","signature":"export const tabsBasePropsSchema","summary":"Props-схема презентационного `Tabs` — единый источник api/props и валидации componentProps.","description":"Props-схема презентационного `Tabs` — единый источник api/props и валидации componentProps.\\n`x-registryName: \'Tabs\'` — каноническое имя в реестре renderer-json.\\nTabs — обёртка над Radix `Tabs.Root`; сериализуемые пропсы взяты из его API\\n(обёртка задаёт default `orientation=\'horizontal\'`). cva-`variant` живёт на `TabsList`, не на Root.","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TabsContent","kind":"function","signature":"function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.tsx","entries":[".","./tabs"],"package":"@reformer/ui-kit"},{"name":"TabsList","kind":"function","signature":"function TabsList({\\n className,\\n variant = \'default\',\\n ...props\\n}: React.ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.tsx","entries":[".","./tabs"],"package":"@reformer/ui-kit"},{"name":"tabsListVariants","kind":"const","signature":"const tabsListVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.tsx","entries":[".","./tabs"],"package":"@reformer/ui-kit"},{"name":"TabsTrigger","kind":"function","signature":"function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tabs/variants/base/tabs-base.tsx","entries":[".","./tabs"],"package":"@reformer/ui-kit"},{"name":"Textarea","kind":"function","signature":"function Textarea({ className, ...props }: React.ComponentProps<\'textarea\'>)","summary":"","params":[],"examplesCount":0,"topics":["overview","text-fields","choice-fields","troubleshooting","form-array-section"],"sourcePath":"src/components/textarea/variants/base/textarea-base.tsx","entries":[".","./textarea"],"package":"@reformer/ui-kit","usage":2},{"name":"TextareaBaseField","kind":"const","signature":"export const TextareaBaseField","summary":"Многострочное строковое поле: pure Textarea + nativeInputAdapter (e.target.value || null).","description":"Многострочное строковое поле: pure Textarea + nativeInputAdapter (e.target.value || null).","params":[],"examplesCount":0,"sourcePath":"src/components/textarea/variants/base/textarea-base.field.tsx","entries":[".","./textarea"],"package":"@reformer/ui-kit"},{"name":"textareaBasePropsSchema","kind":"const","signature":"export const textareaBasePropsSchema","summary":"Props-схема Textarea — многострочный аналог Input (native textarea).","description":"Props-схема Textarea — многострочный аналог Input (native textarea). Единый источник\\n`api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).\\n`x-registryName: \'Textarea\'` — на этот вариант смотрит алиас TextareaField.","params":[],"examplesCount":0,"sourcePath":"src/components/textarea/variants/base/textarea-base.props.ts","entries":[".","./meta","./textarea"],"package":"@reformer/ui-kit"},{"name":"TextareaField","kind":"const","signature":"export const TextareaBaseField","summary":"Многострочное строковое поле: pure Textarea + nativeInputAdapter (e.target.value || null).","description":"Многострочное строковое поле: pure Textarea + nativeInputAdapter (e.target.value || null).","params":[],"examplesCount":0,"topics":["overview","text-fields"],"sourcePath":"src/components/textarea/variants/base/textarea-base.field.tsx","entries":[".","./textarea"],"package":"@reformer/ui-kit","usage":14},{"name":"Toaster","kind":"const","signature":"const Toaster","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sonner/variants/base/sonner-base.tsx","entries":["./sonner"],"package":"@reformer/ui-kit"},{"name":"Toggle","kind":"function","signature":"function Toggle({\\n className,\\n variant,\\n size,\\n ...props\\n}: React.ComponentProps<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>)","summary":"","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/toggle/variants/base/toggle-base.tsx","entries":[".","./toggle"],"package":"@reformer/ui-kit"},{"name":"ToggleBaseField","kind":"const","signature":"export const ToggleBaseField","summary":"Field-версия Toggle: pure shadcn Toggle + `pressedAdapter` (boolean value-based: `pressed` + `onPressedChange`, `null`/`undefined` → `false`).","description":"Field-версия Toggle: pure shadcn Toggle + `pressedAdapter` (boolean value-based:\\n`pressed` + `onPressedChange`, `null`/`undefined` → `false`). Экспортируется как алиас `ToggleField`.\\n\\n⚠️ В ОТЛИЧИЕ от Checkbox/Switch — Toggle НЕ inline-label: подпись поля рисует FormField СВЕРХУ\\n(`componentProps.label` → FormField.Label), а контент toggle (`children`) живёт ВНУТРИ кнопки.\\nПоэтому маркер `reformerLayout=\'inline-label\'` НЕ ставится (иначе верхняя подпись пропала бы).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle/variants/base/toggle-base.field.tsx","entries":[".","./toggle"],"package":"@reformer/ui-kit"},{"name":"toggleBasePropsSchema","kind":"const","signature":"export const toggleBasePropsSchema","summary":"Props-схема Toggle — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема Toggle — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). Поверхность в DSL — `variant`/`size`/`className`;\\n`additionalProperties: false` ловит опечатки. `x-registryName: \'Toggle\'` — алиас `ToggleField`.\\n\\nНЕ inline-label: подпись поля рисует FormField сверху (`componentProps.label`), контент toggle —\\nчерез `children` (несериализуемый, в схему не выносится). `value`/`onChange` переопределяют seam\\nпод boolean-контракт (Radix `pressed`/`onPressedChange`).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle/variants/base/toggle-base.props.ts","entries":[".","./meta","./toggle"],"package":"@reformer/ui-kit"},{"name":"ToggleField","kind":"const","signature":"export const ToggleBaseField","summary":"Field-версия Toggle: pure shadcn Toggle + `pressedAdapter` (boolean value-based: `pressed` + `onPressedChange`, `null`/`undefined` → `false`).","description":"Field-версия Toggle: pure shadcn Toggle + `pressedAdapter` (boolean value-based:\\n`pressed` + `onPressedChange`, `null`/`undefined` → `false`). Экспортируется как алиас `ToggleField`.\\n\\n⚠️ В ОТЛИЧИЕ от Checkbox/Switch — Toggle НЕ inline-label: подпись поля рисует FormField СВЕРХУ\\n(`componentProps.label` → FormField.Label), а контент toggle (`children`) живёт ВНУТРИ кнопки.\\nПоэтому маркер `reformerLayout=\'inline-label\'` НЕ ставится (иначе верхняя подпись пропала бы).","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/toggle/variants/base/toggle-base.field.tsx","entries":[".","./toggle"],"package":"@reformer/ui-kit"},{"name":"ToggleFieldProps","kind":"interface","signature":"export interface ToggleFieldProps {\\n value?: boolean;\\n onChange?: (value: boolean) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n /** Стиль cva: `default` (заливка при нажатии) | `outline` (граница). */\\n variant?: \'default\' | \'outline\';\\n /** Размер cva: `default` | `sm` | `lg`. */\\n size?: \'default\' | \'sm\' | \'lg\';\\n className?: string;\\n /** Контент внутри toggle (иконка/текст). Рендерится в кнопке; НЕ является подписью поля. */\\n children?: React.ReactNode;\\n}","summary":"Value-based контракт field-версии Toggle.","description":"Value-based контракт field-версии Toggle. Значение — `boolean` (нажат/pressed); форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт `variant`/`size`/`className` в `componentProps`,\\nа сам контент (иконка/текст) — через `children`. Служит типом для стража props-схемы\\n(base — Radix `pressed`/`onPressedChange`, не `value`).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle/variants/base/toggle-base.field.tsx","entries":[".","./toggle"],"package":"@reformer/ui-kit"},{"name":"ToggleGroup","kind":"function","signature":"function ToggleGroup({\\n className,\\n variant,\\n size,\\n spacing = 0,\\n children,\\n ...props\\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &\\n VariantProps<typeof toggleVariants> & {\\n spacing?: number;\\n })","summary":"","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit","usage":1},{"name":"ToggleGroupBaseField","kind":"const","signature":"export const ToggleGroupBaseField","summary":"Field-версия ToggleGroup: value-based (`value: string | null`, `onChange(value)`), рендерит `options`.","description":"Field-версия ToggleGroup: value-based (`value: string | null`, `onChange(value)`), рендерит\\n`options`. Привязка через {@link valueChangeAdapter} (`value` / `onValueChange`, string).\\nНЕ inline-label — подпись группы рисует FormField сверху. Экспортируется как алиас `ToggleGroupField`.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"toggleGroupBasePropsSchema","kind":"const","signature":"export const toggleGroupBasePropsSchema","summary":"Props-схема ToggleGroup — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема ToggleGroup — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки. `x-registryName:\\n\'ToggleGroup\'` — на этот вариант смотрит алиас `ToggleGroupField`.\\n\\n`value`/`onChange` переопределяют seam под string-контракт группы (выбранное `option.value`).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.props.ts","entries":[".","./meta","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupField","kind":"const","signature":"export const ToggleGroupBaseField","summary":"Field-версия ToggleGroup: value-based (`value: string | null`, `onChange(value)`), рендерит `options`.","description":"Field-версия ToggleGroup: value-based (`value: string | null`, `onChange(value)`), рендерит\\n`options`. Привязка через {@link valueChangeAdapter} (`value` / `onValueChange`, string).\\nНЕ inline-label — подпись группы рисует FormField сверху. Экспортируется как алиас `ToggleGroupField`.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupFieldProps","kind":"interface","signature":"export interface ToggleGroupFieldProps {\\n value?: string;\\n onChange?: (value: string) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n options?: ToggleGroupOption[];\\n variant?: VariantProps<typeof toggleVariants>[\'variant\'];\\n className?: string;\\n}","summary":"Value-based контракт field-версии ToggleGroup.","description":"Value-based контракт field-версии ToggleGroup. Значение — `string` (`option.value`); форма\\nрезолвит `value`/`onChange`/`onBlur`/`disabled`, автор задаёт `options`/`variant`/`className`\\nв `componentProps`. Служит типом для стража props-схемы (base — Radix `value`/`onValueChange`).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupItem","kind":"function","signature":"function ToggleGroupItem({\\n className,\\n children,\\n variant,\\n size,\\n ...props\\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupMulti","kind":"function","signature":"function ToggleGroupMulti({\\n options = [],\\n value,\\n onChange,\\n maxItems,\\n variant,\\n size,\\n \'data-testid\': dataTestId,\\n ...props\\n}: ToggleGroupMultiProps)","summary":"ToggleGroup в режиме множественного выбора (вариант `multi`).","description":"ToggleGroup в режиме множественного выбора (вариант `multi`).\\n\\nОтдельный компонент, а не проп `multiple` у базового: Radix типизирует `type=\\"single\\"` и\\n`type=\\"multiple\\"` разными ветками union\'а Root\'а (`value: string` против `string[]`), а\\n`ToggleGroupOptions` вдобавок жёстко зашивает `type=\\"single\\"` и `value={value ?? \'\'}`. Главное же\\n— тип значения поля входит в контракт записи каталога: `x-runtimeProps.value` у записи один, и\\n«строка ИЛИ массив в зависимости от соседнего пропа» там невыразимо. Тот же приём и по той же\\nпричине — у `FileUpload` / `FileUploadAvatar`.\\n\\nНаружу выставлен value-based контракт (`value`/`onChange`), а не Radix-shape\\n(`onValueChange`), чтобы field-версия собиралась общим `multiValueAdapter` — тем же, что у\\nтрёх остальных мультивыборов кита.","params":[],"examplesCount":0,"topics":["choice-fields","troubleshooting"],"sourcePath":"src/components/toggle-group/variants/multi/toggle-group-multi.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit","usage":1},{"name":"ToggleGroupMultiField","kind":"const","signature":"export const ToggleGroupMultiField","summary":"Field-версия ToggleGroupMulti: множественный выбор со значением `string[] | null`.","description":"Field-версия ToggleGroupMulti: множественный выбор со значением `string[] | null`.\\nПривязка через {@link multiValueAdapter} — общий для всех мультивыборов кита.\\nНЕ inline-label: подпись группы рисует FormField сверху.","params":[],"examplesCount":0,"topics":["overview","choice-fields"],"sourcePath":"src/components/toggle-group/variants/multi/toggle-group-multi.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit","usage":3},{"name":"ToggleGroupMultiFieldProps","kind":"interface","signature":"export interface ToggleGroupMultiFieldProps {\\n value?: string[] | null;\\n onChange?: (value: string[] | null) => void;\\n onBlur?: () => void;\\n disabled?: boolean;\\n options?: ToggleGroupOption[];\\n maxItems?: number;\\n variant?: VariantProps<typeof toggleVariants>[\'variant\'];\\n className?: string;\\n}","summary":"Value-based контракт field-версии ToggleGroupMulti.","description":"Value-based контракт field-версии ToggleGroupMulti. Значение — `string[] | null`; форма резолвит\\n`value`/`onChange`/`onBlur`/`disabled`, автор задаёт `options`/`maxItems`/`variant`/`className`\\nв `componentProps`. Служит типом для стража props-схемы.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/multi/toggle-group-multi.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupMultiProps","kind":"interface","signature":"export interface ToggleGroupMultiProps {\\n /** Список вариантов. Каждый рендерится как `ToggleGroupItem` (кнопка `role=checkbox`). */\\n options?: ToggleGroupOption[];\\n /**\\n * Выбранные значения. Приходит массивом всегда: `multiValueAdapter` разворачивает `null` в `[]`,\\n * потому что рендер ходит по значению `.includes`/`.length`.\\n */\\n value?: string[];\\n /** Изменение выбора. Всегда получает НОВЫЙ массив — см. `multiValueAdapter`. */\\n onChange?: (value: string[]) => void;\\n onBlur?: () => void;\\n /**\\n * Потолок числа выбранных: по достижении невыбранные кнопки выключаются.\\n *\\n * Это affordance, а НЕ правило формы: авторитетное ограничение задаётся `maxLength(n)` в схеме\\n * валидации. Держать здесь единственный источник истины нельзя — контрол не участвует в submit.\\n */\\n maxItems?: number;\\n variant?: VariantProps<typeof toggleVariants>[\'variant\'];\\n size?: VariantProps<typeof toggleVariants>[\'size\'];\\n className?: string;\\n disabled?: boolean;\\n /** id контейнера (seam — форма связывает подпись). */\\n id?: string;\\n /** Префикс `data-testid`; на контейнер + `-<value>` на каждый Item. */\\n \'data-testid\'?: string;\\n \'aria-invalid\'?: boolean | \'true\' | \'false\';\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n \'aria-errormessage\'?: string;\\n \'aria-required\'?: boolean | \'true\' | \'false\';\\n}","summary":"Props презентационного {@link ToggleGroupMulti}.","description":"Props презентационного {@link ToggleGroupMulti}.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/multi/toggle-group-multi.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"toggleGroupMultiPropsSchema","kind":"const","signature":"export const toggleGroupMultiPropsSchema","summary":"Props-схема ToggleGroupMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема ToggleGroupMulti — единый источник `api.controls[]` (reformer-doc) и DSL-валидации\\n`componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'ToggleGroupMulti\'` — отдельная запись каталога, а не проп у `ToggleGroup`:\\nтип значения другой (`string[] | null` против `string | null`), а `x-runtimeProps.value` у\\nзаписи ровно один. Прецедент — `FileUpload` / `FileUploadAvatar`.\\n\\n`x-variantGroup: \'ToggleGroup\'` (без `x-variant`-совпадения с именем) делает запись НЕдефолтным\\nчленом группы: дефолт — тот, чей `x-registryName === x-variantGroup`.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/multi/toggle-group-multi.props.ts","entries":[".","./meta","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupOption","kind":"interface","signature":"export interface ToggleGroupOption {\\n /** Значение, попадающее в `onChange`. Radix ToggleGroup оперирует строками. */\\n value: string;\\n /** Подпись на кнопке-переключателе. */\\n label: string;\\n}","summary":"Один вариант выбора для {@link ToggleGroupField}.","description":"Один вариант выбора для {@link ToggleGroupField}.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupOptions","kind":"function","signature":"function ToggleGroupOptions({\\n options = [],\\n value,\\n onValueChange,\\n variant,\\n size,\\n \'data-testid\': dataTestId,\\n ...props\\n}: ToggleGroupOptionsProps)","summary":"Презентационная обёртка над base ToggleGroup/ToggleGroupItem: рендерит опции из массива `options` в single-режиме (`type=\\"single\\"` → Radix эмитит выбранную строку).","description":"Презентационная обёртка над base ToggleGroup/ToggleGroupItem: рендерит опции из массива\\n`options` в single-режиме (`type=\\"single\\"` → Radix эмитит выбранную строку). Контракт\\n`value` / `onValueChange` совпадает с Radix Root — поэтому field-версия =\\n`withFormControl(ToggleGroupOptions, valueChangeAdapter)` (без ручного маппинга событий).\\n\\nКонтейнер — Radix Root (`role=\\"group\\"`); каждый Item получает per-option\\n`data-testid = <data-testid>-<value>`: FormField передаёт контролу `data-testid=\\"input-<field>\\"`,\\nпоэтому в форме выходит `input-<field>-<value>` (POM ждёт именно этот идентификатор).\\naria-атрибуты и id приходят через spread `...props` и ложатся на контейнер (seam-контракт).","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"ToggleGroupOptionsProps","kind":"interface","signature":"export interface ToggleGroupOptionsProps {\\n /** Список вариантов. Каждый рендерится как `ToggleGroupItem` (кнопка `role=radio`). */\\n options?: ToggleGroupOption[];\\n /** Выбранное значение (single-режим Radix: `value: string`). */\\n value?: string;\\n /** Radix `onValueChange(string)` — сюда `valueChangeAdapter` кладёт эмиттер. */\\n onValueChange?: (value: string) => void;\\n /** Визуальный стиль кнопок (`default` — плоские, `outline` — с рамкой). */\\n variant?: VariantProps<typeof toggleVariants>[\'variant\'];\\n /** Размер кнопок. */\\n size?: VariantProps<typeof toggleVariants>[\'size\'];\\n /** Доп. CSS-класс контейнера группы. */\\n className?: string;\\n /** id контейнера (seam — форма связывает подпись). */\\n id?: string;\\n /** Префикс `data-testid`; на контейнер + `-<value>` на каждый Item. */\\n \'data-testid\'?: string;\\n}","summary":"Props презентационной обёртки {@link ToggleGroupOptions}.","description":"Props презентационной обёртки {@link ToggleGroupOptions}.","params":[],"examplesCount":0,"sourcePath":"src/components/toggle-group/variants/base/toggle-group-base.field.tsx","entries":[".","./toggle-group"],"package":"@reformer/ui-kit"},{"name":"toggleVariants","kind":"const","signature":"const toggleVariants","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/toggle/variants/base/toggle-base.tsx","entries":[".","./toggle"],"package":"@reformer/ui-kit"},{"name":"Tooltip","kind":"function","signature":"function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tooltip/variants/base/tooltip-base.tsx","entries":[".","./tooltip"],"package":"@reformer/ui-kit"},{"name":"tooltipBasePropsSchema","kind":"const","signature":"export const tooltipBasePropsSchema","summary":"Props-схема Tooltip (Radix Tooltip.Root) — провайдер без DOM (стили/позиция — на TooltipContent).","description":"Props-схема Tooltip (Radix Tooltip.Root) — провайдер без DOM (стили/позиция — на TooltipContent).","params":[],"examplesCount":0,"sourcePath":"src/components/tooltip/variants/base/tooltip-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TooltipContent","kind":"function","signature":"function TooltipContent({\\n className,\\n sideOffset = 0,\\n children,\\n ...props\\n}: React.ComponentProps<typeof TooltipPrimitive.Content>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tooltip/variants/base/tooltip-base.tsx","entries":[".","./tooltip"],"package":"@reformer/ui-kit"},{"name":"TooltipProvider","kind":"function","signature":"function TooltipProvider({\\n delayDuration = 0,\\n ...props\\n}: React.ComponentProps<typeof TooltipPrimitive.Provider>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tooltip/variants/base/tooltip-base.tsx","entries":[".","./tooltip"],"package":"@reformer/ui-kit"},{"name":"TooltipTrigger","kind":"function","signature":"function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tooltip/variants/base/tooltip-base.tsx","entries":[".","./tooltip"],"package":"@reformer/ui-kit"},{"name":"Tree","kind":"const","signature":"const Tree","summary":"Tree (вариант `base`) — плотное дерево с уровнями, как файловый навигатор редактора.","description":"Tree (вариант `base`) — плотное дерево с уровнями, как файловый навигатор редактора.\\n\\nУровни читаются лениво: {@link TreeProps.loadChildren} вызывается при первом раскрытии\\nветки, прочитанное запоминается. Строки фиксированной высоты и виртуальный скролл — не\\nмикрооптимизация: раскрытый каталог проекта это тысячи строк, и каждая несёт обработчики.\\n\\nКлавиатура принадлежит дереву и глушится (`stopPropagation`): стрелки, `Home`/`End`,\\n`Enter`, пробел, `Escape`. Сочетания с модификатором уходят наверх целиком — перехватив\\n`mod+c`, дерево отняло бы у команды копирования её единственную дверь.","params":[],"example":"Статическое дерево, выбор только файлов\\n```tsx\\n<Tree nodes={nodes} selectable=\\"leaf\\" onActivate={(n) => open(n.id)} />\\n```","examplesCount":2,"topics":["overview","choice-fields","layout-and-buttons","troubleshooting","imperative-handles"],"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit","usage":16},{"name":"TREE_ROW_ATTRIBUTE","kind":"const","signature":"const ROW_ATTRIBUTE","summary":"Атрибут адреса на строке.","description":"Атрибут адреса на строке. По нему потребитель находит свою строку в обработчике, который\\nрисуется вне дерева, — например в контекстном меню, чьё содержимое Radix монтирует порталом.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TREE_ROW_HEIGHT","kind":"const","signature":"const ROW_HEIGHT","summary":"Высота строки, px.","description":"Высота строки, px. Фиксирована — на ней стоит виртуальный скролл.","params":[],"examplesCount":0,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeActivateMeta","kind":"interface","signature":"export interface TreeActivateMeta {\\n /**\\n * Предпросмотр. `true` — одиночный щелчок или пробел, `false` — двойной щелчок или Enter.\\n * Различение взято у редакторов кода: одиночный щелчок открывает файл временной вкладкой,\\n * двойной закрепляет её. Потребителю, которому это не нужно, достаточно не смотреть в поле.\\n */\\n readonly preview: boolean;\\n}","summary":"Обстоятельства запуска строки.","description":"Обстоятельства запуска строки.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeBadgeTone","kind":"type","signature":"export type TreeBadgeTone = \'default\' | \'secondary\' | \'destructive\' | \'outline\';","summary":"Оформление метки строки — те же тона, что у {@link Badge}.","description":"Оформление метки строки — те же тона, что у {@link Badge}.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"treeBasePropsSchema","kind":"const","signature":"export const treeBasePropsSchema","summary":"Props-схема презентационного `Tree` — единый источник `api.controls[]` (reformer-doc) и DSL-валидации `componentProps` (renderer-json).","description":"Props-схема презентационного `Tree` — единый источник `api.controls[]` (reformer-doc) и\\nDSL-валидации `componentProps` (renderer-json). `additionalProperties: false` ловит опечатки.\\n\\n`x-registryName: \'Tree\'` — каноническое имя в реестре renderer-json.\\n\\nДерево — не поле формы: у него нет `value`/`onChange`, и `*Field`-обёртки у него тоже нет.\\nВыбор файла формой делает вариант комбобокса (`ComboboxTree`), который это дерево использует\\nвнутри: поле обязано отдавать ОДНО значение, а дерево — навигация, у которой значений\\nстолько же, сколько строк.\\n\\nОписание узла — общий фрагмент с вариантами комбобокса, см. `./tree-node-schema`.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-base.props.ts","entries":[".","./meta","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeHandle","kind":"interface","signature":"export interface TreeHandle extends FieldHandle {\\n /** Раскрывает ветку, дочитывая уровень, если он ещё не прочитан. */\\n expand(id: string): Promise<void>;\\n collapse(id: string): void;\\n /** Раскрывает или сворачивает — то, что делает щелчок по треугольнику. */\\n toggle(id: string): Promise<void>;\\n /**\\n * Перечитывает уровень: файл создан, удалён, переименован. `null` — верхний уровень.\\n * Без него ленивое дерево держало бы устаревший снимок до перемонтирования.\\n */\\n refresh(id?: string | null): Promise<void>;\\n /** Выделяет строку, доводит её до видимой области и ставит на неё фокус. */\\n focusNode(id: string): void;\\n /** Видимый ряд строк — то, из чего потребитель считает цель действия. */\\n getRows(): readonly TreeRow[];\\n /** К чему применится действие: набор, если выделение внутри него, иначе одна строка. */\\n getActionTargets(): readonly TreeNode[];\\n}","summary":"Императивный handle {@link Tree}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/ getElement на контейнере дерева) + управление уровнями и фокусом строки.","description":"Императивный handle {@link Tree}: baseline {@link FieldHandle} (focus/blur/scrollIntoView/\\ngetElement на контейнере дерева) + управление уровнями и фокусом строки.","params":[],"examplesCount":0,"topics":["layout-and-buttons","imperative-handles"],"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeIconRenderer","kind":"type","signature":"export type TreeIconRenderer = (node: TreeNode, state: TreeRenderState) => React.ReactNode;","summary":"Значок строки.","description":"Значок строки. Вынесен из отрисовки, потому что им подменяют умолчание: «это схема формы»\\nзнает потребитель, а не дерево.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeNode","kind":"interface","signature":"export interface TreeNode {\\n /** Адрес узла, уникальный в пределах всего дерева: по нему идут раскрытие, выбор и фокус. */\\n id: string;\\n /** Видимая подпись строки. По ней же идёт поиск. */\\n label: string;\\n /** Ветка или лист. */\\n kind?: TreeNodeKind;\\n /** Дети. У ветки `undefined` означает «уровень не прочитан», а не «детей нет». */\\n children?: readonly TreeNode[];\\n /** Метка справа от подписи. */\\n badge?: string;\\n /** Тон метки. */\\n badgeTone?: TreeBadgeTone;\\n /** Подсказка при наведении. По умолчанию — `label`. */\\n title?: string;\\n /** Строку нельзя выбрать. Раскрыть ветку по-прежнему можно: это осмотр, а не выбор. */\\n disabled?: boolean;\\n /**\\n * Уровень читается прямо сейчас — вместо треугольника показывается спиннер.\\n *\\n * Объявляется узлом, а не только выводится из внутреннего чтения, ради потребителей,\\n * у которых загрузка уровней уже своя: дерево с чужим хранилищем обязано уметь показать\\n * его состояние, не отбирая у него это хранилище.\\n */\\n loading?: boolean;\\n /** Уровень не прочитался: нет прав, каталог исчез. Подпись становится тревожной. */\\n failed?: boolean;\\n}","summary":"Узел дерева.","description":"Узел дерева.\\n\\n`kind` объявляется, а не выводится из `children`: у ленивой ветки детей ещё нет, и пустой\\nкаталог был бы неотличим от файла. Умолчание — `\'branch\'`, если поле `children` присутствует,\\nиначе `\'leaf\'`.","params":[],"examplesCount":0,"topics":["choice-fields","layout-and-buttons","troubleshooting"],"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit","usage":5},{"name":"TreeNodeKind","kind":"type","signature":"export type TreeNodeKind = \'branch\' | \'leaf\';","summary":"Вид узла: ветка раскрывается, лист — нет.","description":"Вид узла: ветка раскрывается, лист — нет.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeProps","kind":"interface","signature":"export interface TreeProps {\\n className?: string;\\n /**\\n * Узлы верхнего уровня. Не задан вместе с {@link TreeProps.loadChildren} — верхний уровень\\n * дерево прочитает само при появлении, передав в загрузчик `null`.\\n */\\n nodes?: readonly TreeNode[];\\n /**\\n * Ленивое чтение уровня: вызывается при первом раскрытии ветки; `null` — верхний уровень.\\n * Прочитанный уровень запоминается: свернуть и раскрыть обратно обращения не стоит.\\n */\\n loadChildren?: (node: TreeNode | null) => Promise<readonly TreeNode[]>;\\n /** Раскрытые ветки (управляемо). Без него дерево держит раскрытие само. */\\n expandedIds?: readonly string[];\\n /** Раскрытые ветки на старте (неуправляемо). */\\n defaultExpandedIds?: readonly string[];\\n onExpandedChange?: (ids: string[]) => void;\\n /** Выделенный узел (управляемо). Выделение — «где я сейчас», одна строка. */\\n selectedId?: string | null;\\n /** Выделенный узел на старте (неуправляемо). */\\n defaultSelectedId?: string | null;\\n onSelectedChange?: (id: string | null) => void;\\n /**\\n * Отмеченный набор (управляемо) — «что я выбрал», к чему применится действие.\\n *\\n * Отдельно от {@link TreeProps.selectedId}, потому что это разные вещи: выделение — одна\\n * строка, туда же уходит фокус; набор — сколько угодно строк, и строка с фокусом может\\n * в него не входить. Свести их в один список нельзя: тогда «где я» теряет ответ, а\\n * клавиатурная навигация — точку отсчёта для диапазона.\\n */\\n checkedIds?: readonly string[];\\n /** Отмеченный набор на старте (неуправляемо). */\\n defaultCheckedIds?: readonly string[];\\n onCheckedChange?: (ids: string[]) => void;\\n /** Режим выбора. По умолчанию `\'single\'`. */\\n selectionMode?: TreeSelectionMode;\\n /** Как строка попадает в набор при `selectionMode=\'multiple\'`. По умолчанию `\'modifier\'`. */\\n checkOn?: TreeCheckOn;\\n /** Что можно выбрать. По умолчанию `\'all\'`; `\'leaf\'` — режим выбора файла. */\\n selectable?: TreeSelectable;\\n /**\\n * Дополнительный запрет выбора поверх `node.disabled`. Для запретов ДИНАМИЧЕСКИХ, которых\\n * в данных узла быть не может: достигнутый потолок числа выбранных, права на конкретный файл.\\n */\\n isNodeDisabled?: (node: TreeNode) => boolean;\\n /**\\n * Запуск строки. Ветку дерево раскрывает само и наружу не сообщает: раскрытие — осмотр,\\n * а не действие над узлом, и потребителю не приходится знать про состояние, которым он\\n * не управляет.\\n */\\n onActivate?: (node: TreeNode, meta: TreeActivateMeta) => void;\\n /**\\n * Щелчок по строке ДО того, как дерево применит свои правила выбора. Вызвавший\\n * `event.preventDefault()` берёт строку себе целиком — так потребитель со своими правилами\\n * (диапазоны, наборы, свои модификаторы) остаётся хозяином, не отказываясь от отрисовки.\\n */\\n onRowClick?: (node: TreeNode, event: React.MouseEvent) => void;\\n /** Двойной щелчок ДО запуска строки; `preventDefault` отменяет запуск. */\\n onRowDoubleClick?: (node: TreeNode, event: React.MouseEvent) => void;\\n /** Правый щелчок по дереву целиком: строку потребитель находит по `data-tree-id`. */\\n onContextMenu?: React.MouseEventHandler<HTMLDivElement>;\\n /** Доп. атрибуты строки: свои `data-*`, `title`, обработчики. */\\n getRowProps?: (\\n node: TreeNode,\\n row: TreeRow\\n ) => React.HTMLAttributes<HTMLElement> & Record<string, unknown>;\\n /**\\n * Поисковый запрос. Оставляет узлы, чей `label` содержит подстроку, и достраивает до них\\n * путь; ветки на пути раскрываются на время поиска и возвращаются в прежнее состояние,\\n * когда запрос убран. Видит только прочитанные уровни.\\n */\\n search?: string;\\n /** Текст пустого дерева. По умолчанию `\'Пусто\'`. */\\n emptyText?: string;\\n /** Высота строки, px. По умолчанию 24. */\\n rowHeight?: number;\\n /**\\n * Сколько строк показать, прежде чем включится прокрутка. Задаёт дереву ОПРЕДЕЛЁННУЮ высоту\\n * по содержимому — то, что нужно списку в поповере: короткое дерево не оставляет пустоты,\\n * длинное не растёт бесконечно. Без него высоту задаёт вызывающий через `className`\\n * (например `h-full` в панели), и прокрутка появляется от неё.\\n */\\n maxRows?: number;\\n /** Отступ уровня, px. По умолчанию 12. */\\n indent?: number;\\n /** Отступ первого уровня от левого края, px. По умолчанию 8. */\\n indentBase?: number;\\n /**\\n * Виртуальный скролл. По умолчанию включён: раскрытый каталог реального проекта — тысячи\\n * строк. Выключают там, где дерево заведомо короткое, а разметка нужна целиком, — например\\n * при серверной отрисовке страницы документации.\\n */\\n virtualized?: boolean;\\n /** Значок строки; возврат `undefined`/`null` оставляет умолчание (каталог/файл). */\\n renderIcon?: TreeIconRenderer;\\n /** Подпись строки; возврат `undefined`/`null` оставляет `node.label`. */\\n renderLabel?: (node: TreeNode, state: TreeRenderState) => React.ReactNode;\\n /** Содержимое правого края строки: свои метки, кнопки, подсказки. */\\n renderActions?: (node: TreeNode, state: TreeRenderState) => React.ReactNode;\\n /** Отказ чтения уровня. По умолчанию пишется в консоль: молчание здесь хуже шума. */\\n onLoadError?: (error: unknown, node: TreeNode | null) => void;\\n /** id контейнера дерева — по нему подпись снаружи связывается с деревом. */\\n id?: string;\\n /** Префикс `data-testid`: на корне, `-<id узла>` на строке, `-<id узла>-chevron` на треугольнике. */\\n \'data-testid\'?: string;\\n \'aria-label\'?: string;\\n \'aria-labelledby\'?: string;\\n \'aria-describedby\'?: string;\\n}","summary":"Props компонента {@link Tree}.","description":"Props компонента {@link Tree}.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeRow","kind":"interface","signature":"export interface TreeRow {\\n readonly node: TreeNode;\\n /** Глубина от корня; узлы верхнего уровня — `0`. */\\n readonly depth: number;\\n /** Раскрыта ли ветка. У листа всегда `false`. */\\n readonly expanded: boolean;\\n /** Уровень читается прямо сейчас. */\\n readonly loading: boolean;\\n /** Уровень не прочитался: нет прав, каталог исчез. */\\n readonly failed: boolean;\\n readonly selected: boolean;\\n /** Входит ли строка в отмеченный набор. */\\n readonly checked: boolean;\\n /** Ветка ли это — считано один раз, чтобы отрисовка не повторяла правило. */\\n readonly branch: boolean;\\n /**\\n * Строку нельзя выбрать: так объявлено узлом либо так решил предикат дерева. Считается\\n * здесь, а не в отрисовке, потому что тот же ответ нужен клавиатуре и правилам выбора —\\n * а два места, отвечающие на один вопрос, рано или поздно отвечают по-разному.\\n */\\n readonly disabled: boolean;\\n /** Адрес родителя; у верхнего уровня — `null`. Нужен стрелке «влево». */\\n readonly parentId: string | null;\\n}","summary":"Строка видимого ряда — то, что дерево отрисовывает.","description":"Строка видимого ряда — то, что дерево отрисовывает.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-model.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeSelectable","kind":"type","signature":"export type TreeSelectable = \'all\' | \'leaf\';","summary":"Что можно выбирать: любой узел или только листья.","description":"Что можно выбирать: любой узел или только листья.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TreeSelectionMode","kind":"type","signature":"export type TreeSelectionMode = \'single\' | \'multiple\';","summary":"Режим выбора: один узел (курсор) или курсор плюс отмеченный набор.","description":"Режим выбора: один узел (курсор) или курсор плюс отмеченный набор.","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/tree-base.tsx","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"TypographyBlockquote","kind":"function","signature":"function TypographyBlockquote({ className, ...props }: React.ComponentProps<\'blockquote\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyBlockquotePropsSchema","kind":"const","signature":"export const typographyBlockquotePropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyH1","kind":"function","signature":"function TypographyH1({ className, ...props }: React.ComponentProps<\'h1\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyH1PropsSchema","kind":"const","signature":"export const typographyH1PropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyH2","kind":"function","signature":"function TypographyH2({ className, ...props }: React.ComponentProps<\'h2\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyH2PropsSchema","kind":"const","signature":"export const typographyH2PropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyH3","kind":"function","signature":"function TypographyH3({ className, ...props }: React.ComponentProps<\'h3\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyH3PropsSchema","kind":"const","signature":"export const typographyH3PropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyH4","kind":"function","signature":"function TypographyH4({ className, ...props }: React.ComponentProps<\'h4\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyH4PropsSchema","kind":"const","signature":"export const typographyH4PropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyInlineCode","kind":"function","signature":"function TypographyInlineCode({ className, ...props }: React.ComponentProps<\'code\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyInlineCodePropsSchema","kind":"const","signature":"export const typographyInlineCodePropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyLarge","kind":"function","signature":"function TypographyLarge({ className, ...props }: React.ComponentProps<\'div\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyLargePropsSchema","kind":"const","signature":"export const typographyLargePropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyLead","kind":"function","signature":"function TypographyLead({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyLeadPropsSchema","kind":"const","signature":"export const typographyLeadPropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyList","kind":"function","signature":"function TypographyList({ className, ...props }: React.ComponentProps<\'ul\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyListPropsSchema","kind":"const","signature":"export const typographyListPropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyMuted","kind":"function","signature":"function TypographyMuted({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyMutedPropsSchema","kind":"const","signature":"export const typographyMutedPropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographyP","kind":"function","signature":"function TypographyP({ className, ...props }: React.ComponentProps<\'p\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographyPPropsSchema","kind":"const","signature":"export const typographyPPropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"TypographySmall","kind":"function","signature":"function TypographySmall({ className, ...props }: React.ComponentProps<\'small\'>)","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.tsx","entries":[".","./typography"],"package":"@reformer/ui-kit"},{"name":"typographySmallPropsSchema","kind":"const","signature":"export const typographySmallPropsSchema","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/typography/variants/base/typography-base.props.ts","entries":["./meta"],"package":"@reformer/ui-kit"},{"name":"useChart","kind":"function","signature":"function useChart()","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/chart/variants/base/chart-base.tsx","entries":["./chart"],"package":"@reformer/ui-kit"},{"name":"useDirection","kind":"const","signature":"const useDirection","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/direction/variants/base/direction-base.tsx","entries":[".","./direction"],"package":"@reformer/ui-kit"},{"name":"useSidebar","kind":"function","signature":"function useSidebar()","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/sidebar/variants/base/sidebar-base.tsx","entries":["./sidebar"],"package":"@reformer/ui-kit"},{"name":"useVirtualRows","kind":"function","signature":"export function useVirtualRows(count: number, rowHeight: number, overscan = 8): VirtualRows","summary":"Окно видимых строк списка из `count` строк по `rowHeight` пикселей.","description":"Окно видимых строк списка из `count` строк по `rowHeight` пикселей.","params":[],"example":"const rows = useVirtualRows(items.length, 24);\\n<ScrollArea ref={rows.scrollRef}>\\n <div style={{ height: rows.totalHeight }}>\\n <div style={{ transform: `translateY(${rows.offsetTop}px)` }}>\\n {items.slice(rows.start, rows.end).map(renderRow)}\\n </div>\\n </div>\\n</ScrollArea>","examplesCount":1,"topics":["layout-and-buttons"],"sourcePath":"src/components/tree/variants/base/use-virtual-rows.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"valueChangeAdapter","kind":"const","signature":"export const valueChangeAdapter: FieldAdapter","summary":"Select / Radio Group / Toggle Group — `value` + `onValueChange(string)`.","description":"Select / Radio Group / Toggle Group — `value` + `onValueChange(string)`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/adapters.ts","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"VirtualRows","kind":"interface","signature":"export interface VirtualRows extends RowRange {\\n /** Вешается на контейнер со скроллом. */\\n readonly scrollRef: React.RefObject<HTMLDivElement | null>;\\n /** Высота всего списка — распорка, которая держит скроллбар честным. */\\n readonly totalHeight: number;\\n /** Сдвиг окна от начала списка. */\\n readonly offsetTop: number;\\n /** Доводит строку до видимой области, если она за краем. */\\n readonly scrollToRow: (index: number) => void;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/components/tree/variants/base/use-virtual-rows.ts","entries":[".","./tree"],"package":"@reformer/ui-kit"},{"name":"withFormControl","kind":"function","signature":"export function withFormControl<P extends object, H extends FieldHandle = FieldHandle>(\\n Primitive: ComponentType<P>,\\n adapter: FieldAdapter,\\n options?: WithFormControlOptions<H>\\n): ForwardRefExoticComponent<Record<string, unknown> & RefAttributes<H>>","summary":"HOC: превращает чистый shadcn-примитив в field-компонент по контракту seam.","description":"HOC: превращает чистый shadcn-примитив в field-компонент по контракту seam.\\n\\nПод `<FormField control={…}/>` (@reformer/cdk) и в renderer-react компонент получает\\nplain props, резолвленные выше: `value` (raw), value-based `onChange:(value)=>void`,\\n`onBlur`, `disabled`, `id`, `aria-*`, весь `componentProps` кроме `testId`.\\n\\nHOC отбрасывает `control` (renderer-react дополнительно передаёт `control={fieldNode}` — в DOM\\nон не нужен) и любые `strip`-ключи, чтобы ничего не текло в DOM, и маппит value/onChange под\\nevent-shape примитива через {@link FieldAdapter}.\\n\\nКомпонент — `forwardRef` и экспонирует императивный {@link FieldHandle}: по умолчанию baseline\\n(focus/blur/scrollIntoView/getElement из DOM-узла примитива), либо handle композита при\\n`options.exposesHandle`. Ref достаётся из render-схемы через `schema.node(sel).getRef()`.","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/with-form-control.tsx","entries":["./fields"],"package":"@reformer/ui-kit"},{"name":"WithFormControlOptions","kind":"interface","signature":"export interface WithFormControlOptions<H extends FieldHandle = FieldHandle> {\\n /**\\n * Композит сам реализует императивный handle (`useImperativeHandle`). Тогда ref потребителя\\n * форвардится ПРЯМО в примитив (passthrough), а HOC не вешает свой `useImperativeHandle` —\\n * иначе один ref писался бы дважды (последний писатель побеждает).\\n */\\n exposesHandle?: boolean;\\n /** Переопределить baseline-handle. По умолчанию — {@link makeElementFieldHandle} из DOM-узла примитива. */\\n buildHandle?: (el: RefObject<HTMLElement | null>) => H;\\n}","summary":"Опции handle-слоя HOC (см.","description":"Опции handle-слоя HOC (см. docs/plans/useimperativehandle-refactored-blossom.md).","params":[],"examplesCount":0,"topics":["imperative-handles"],"sourcePath":"src/fields/with-form-control.tsx","entries":["./fields"],"package":"@reformer/ui-kit"}]},"@reformer/renderer-react":{"schemaVersion":1,"package":"@reformer/renderer-react","version":"6.0.0","topics":[{"id":"overview","file":"01-overview.md","title":"Overview","purpose":"`@reformer/renderer-react` — рендерер форм для React. Принимает `RenderSchema` (единое декларативное дерево узлов) и отрисовывает компоненты, связывая их с реактивным состоянием формы из `@reformer/core`.","keyConcepts":["**`RenderSchemaFn<T>`** — `() => RenderNode<T>`. Возвращает корневой узел дерева. Аргумента-пути нет: привязка к данным идёт через сигналы модели в листьях.","**`RenderNode<T>`** — узел дерева, дискриминированный union: **field** (`ModelFieldRenderNode` — есть `value: Signal`), **array** (`ArrayRenderNode` — есть `array` + `item`), **container** (`ContainerRenderNode` — есть `component` + `children`).","**`fieldWrapper`** — общая обёртка вокруг каждого поля (label, error). Передаётся через `settings`. Можно перекрыть для конкретного поля через `componentProps.fieldWrapper`.","**`resolveFieldAdapter` / `FieldAdapter`** — вторая настройка `settings` (рядом с `fieldWrapper`): по компоненту поля (`node.component`) резолвит адаптер, который переводит value-based seam рендерера (`value` + `onChange(value)`) в диалект сырого контрола (`checked` + `onChange(event)`, `value` + `onChange(value, option)`, `value` + `onChange(event)` и т.д.). Позволяет регистрировать СЫРЫЕ контролы любого UI-kit, не оборачивая каждый; нет адаптера → seam применяется как есть (обратная совместимость, текущее поведение). Рецепт — [05-cookbook.md](05-cookbook.md).","**`createRenderSchema(fn)`** — превращает `RenderSchemaFn` в `RenderSchemaProxy` для программного управления узлами (`setHidden`, `patchProps`, `getRef`) и точкой подключения декларативного behavior.","**`RenderBehaviorFn<T>`** — функция `(schema) => void`, применяющая standalone-хелперы (`hideWhen`, `renderEffect`, `onComponentEvent`, `onInit`, `onMount`, `onUnmount`) к `RenderSchemaProxy`."],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-render-schema.md](02-render-schema.md) — формат `RenderSchemaFn`, `RenderNode`, массивы.","[03-render-behavior.md](03-render-behavior.md) — hideWhen, renderEffect, lifecycle.","[04-troubleshooting.md](04-troubleshooting.md) — частые ошибки.","[05-cookbook.md](05-cookbook.md) — рецепты из реального кода."],"sections":[{"heading":"Installation","slug":"installation"},{"heading":"Import Patterns","slug":"import-patterns"},{"heading":"Quick Start","slug":"quick-start"},{"heading":"Key Concepts","slug":"key-concepts"},{"heading":"Components and exports","slug":"components-and-exports"},{"heading":"See also","slug":"see-also"}],"terms":[["componentprops",13],["value",10],["reformer",9],["react",9],["rendernode",9],["component",9],["children",9],["form",8],["render",7],["myform",7],["type",6],["wizard",6],["для",5],["model",5],["formrenderer",5],["import",5],["через",5],["renderer",4],["дерево",4],["createreactform",4],["hidewhen",4],["rendereffect",4],["renderschemafn",4],["from",4],["узел",4],["поля",4],["section",4],["email",4],["password",4],["title",4],["schema",4],["settings",4],["fieldwrapper",4],["есть",4],["onchange",4],["cookbook",4],["behavior",4],["рендерер",3],["core",3],["модели",3],["форму",3],["createrenderschema",3],["oncomponentevent",3],["схемы",3],["без",3],["harvest",3],["usereactform",3],["inputfield",3],["kit",3],["label",3],["node",3],["рендер",3],["принимает",2],["формы",2],["схема",2],["него",2],["лист",2],["этому",2],["дереву",2],["один",2],["бандл",2],["typescript",2],["сборка",2],["идёт",2],["одним",2],["вызовом",2],["рендерится",2],["резолвит",2],["сигналу",2],["реестр",2],["который",2],["неё",2],["как",2],["formmodel",2],["box",2],["formfield",2],["string",2],["field",2],["function",2],["buildschema",2],["return",2],["форма",2],["const",2],["программное",2],["управление",2],["body",2],["рецепт",2],["container",2],["nodes",2],["дерева",2],["нет",2],["array",2],["seam",2],["event",2],["renderschemaproxy",2],["хелперы",2],["oninit",2],["onmount",2],["onunmount",2],["узла",2],["troubleshooting",2]]},{"id":"render-schema","file":"02-render-schema.md","title":"Render Schema","purpose":"Единая схема (M1): одно дерево `RenderNode` описывает и layout, и привязку полей к модели. Привязка идёт через **сигналы модели** (`model.$.<field>`), а не через отдельный `path`-прокси.","keyConcepts":["**`RenderSchemaFn<T>`** — `() => RenderNode<T>`. Без аргументов: возвращает корневой узел. Привязка к данным — через сигналы в листьях, поэтому legacy-аргумент `path` удалён.","**`ModelFieldRenderNode`** — узел-поле. Несёт `value: Signal` (сигнал модели, `model.$.<field>`), `component` (UI-компонент), `componentProps` (пропсы поля). State-нода (errors/disabled/validation) резолвится по сигналу через реестр `getNodeForSignal` (реестр заполняет `createForm`). Поля `validators` у узла **НЕТ** — правила валидации значений живут в отдельной TS-схеме над моделью, а не в render-дереве (`validators: [...]` на листе даст `TS2353`; см. [06-validation.md](06-validation.md)). Компонент листа получает **value-based seam** (`control`, `value`, `disabled`, `onChange(value)`, `onBlur`) — value-based контролам настройка не нужна. Сырой контрол сторонней UI-kit с другим диалектом (`checked`+событие у Checkbox, `(value, option)` у Select) подключается через `FieldAdapter`: рендерер сам переложит seam на его контракт, не оборачивая контрол (`settings.resolveFieldAdapter`; см. [05-cookbook.md](05-cookbook.md)).","**`ArrayRenderNode<T>`** — узел-массив модели. Данные принадлежат модели (`array: model.<path>`), форма элемента описывается `item(itemModel)`, `initialValue` — значение/фабрика нового элемента.","**`ContainerRenderNode<T>`** — узел-контейнер. В `component` — React-компонент **либо нативный HTML-тег строкой** (`\'div\'`, `\'h3\'`, `\'hr\'`), содержимое задаётся в **top-level** `children` (НЕ в `componentProps`): вложенные узлы и текстовые части (`RenderChild`) вперемешку."],"api":"","patterns":[],"antiPatterns":[{"note":"- **Возвращать React-element вместо `RenderNode`** — `RenderSchemaFn` должна возвращать описание (`{ component, componentProps, children }` или `{ value, component }`), а не JSX. Сам JSX строит `FormRenderer`.\\n- **Класть `children` в `componentProps`** — `children` это TOP-LEVEL свойство контейнера. Рендерер деструктурирует `const { children } = node`. В `componentProps.children` узлы не отрисуются.\\n- **Хранить `RenderSchemaProxy` внутри компонента без `useMemo`** — на каждом ре-рендере создаётся новый proxy, что ломает override-карты и lifecycle-хуки.\\n- **Забыть `createForm` перед рендером** — лист-узел резолвит state-ноду по сигналу через реестр. Без `createForm({ model, schema })` реестр пуст, поле логирует warning и рендерится как `null`.\\n- **Заводить компонент ради статичного блока текста** — `{ component: \'div\', children: [{ component: \'p\', children: [\'…\'] }] }` описывает то же самое схемой; отдельный компонент нужен, когда есть своя логика или состояние.\\n- **Ожидать реактивности от интерполяции строкой** — `children: [\\\\`Платёж: ${model.$.x.value} ₽\\\\`]` читает значение ОДИН раз при построении схемы. Реактивен только сам сигнал: `children: [\'Платёж: \', model.$.x, \' ₽\']`."}],"examples":[{"lang":"tsx","code":"import type { FormModel } from \'@reformer/core\';\\nimport type { RenderSchemaFn } from \'@reformer/renderer-react\';\\nimport { Box, Section, InputField } from \'@reformer/ui-kit\';\\n\\nconst buildSchema = (model: FormModel<MyForm>): RenderSchemaFn<MyForm> => {\\n return () => ({\\n component: Box,\\n componentProps: { className: \'grid grid-cols-2 gap-4\' },\\n children: [\\n {\\n component: Section,\\n componentProps: { title: \'Личные данные\', className: \'space-y-4\' },\\n children: [\\n { value: model.$.firstName, component: InputField, componentProps: { label: \'Имя\' } },\\n { value: model.$.lastName, component: InputField, componentProps: { label: \'Фамилия\' } },\\n ],\\n },\\n ],\\n });\\n};"}],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md) — mount-путь и `FormRenderer`.","[03-render-behavior.md](03-render-behavior.md) — `hideWhen`, `renderEffect`, lifecycle.","[06-validation.md](06-validation.md) — валидация значений отдельной model-схемой (у RenderNode нет `validators`).","[04-troubleshooting.md](04-troubleshooting.md).","[05-cookbook.md](05-cookbook.md) — `resolveFieldAdapter`/`FieldAdapter`: подключение сырых контролов сторонней UI-kit без per-контрол обёрток."],"sections":[{"heading":"Key Concepts","slug":"key-concepts-2"},{"heading":"Examples","slug":"examples"},{"heading":"Programmatic API","slug":"programmatic-api"},{"heading":"Anti-patterns","slug":"anti-patterns"},{"heading":"See also","slug":"see-also-2"}],"terms":[["component",30],["children",26],["componentprops",21],["model",20],["array",19],["value",17],["node",16],["компонент",14],["schema",13],["для",13],["item",12],["модели",11],["reformer",11],["string",11],["renderer",10],["узел",9],["массив",9],["react",9],["render",8],["path",8],["без",8],["узла",8],["kit",8],["элемента",8],["div",8],["через",7],["рендерер",7],["import",7],["from",7],["section",7],["rendernode",6],["текст",6],["selector",6],["добавить",6],["form",6],["renderschemafn",5],["сигнал",5],["validation",5],["его",5],["initialvalue",5],["top",5],["level",5],["узлы",5],["type",5],["classname",5],["или",5],["при",5],["hidewhen",5],["button",5],["inputfield",5],["formarray",5],["key",4],["привязка",4],["поэтому",4],["реестр",4],["createform",4],["нет",4],["сам",4],["cookbook",4],["поддерево",4],["это",4],["схемы",4],["tsx",4],["box",4],["const",4],["title",4],["label",4],["под",4],["add",4],["behavior",4],["удалить",4],["канон",4],["items",4],["extra",4],["formrenderer",4],["overview",4],["описывает",3],["полей",3],["сигналы",3],["field",3],["отдельный",3],["disabled",3],["validators",3],["контрол",3],["контракт",3],["форма",3],["itemmodel",3],["значение",3],["фабрика",3],["нового",3],["либо",3],["текстовые",3],["части",3],["реактивный",3],["платёж",3],["myform",3],["space",3],["строит",3],["кнопки",3],["секции",3],["remove",3],["itemlabel",3],["элементы",3],["проп",3],["arraycomponentprops",3],["onadd",3],["onremove",3],["jsx",3],["createrenderschema",3],["lifecycle",3],["схема",2],["дерево",2],["идёт",2],["поле",2],["signal",2],["поля",2],["state",2],["нода",2],["сигналу",2],["значений",2],["отдельной",2],["схеме",2],["дереве",2],["получает",2],["based",2],["seam",2],["сторонней",2],["fieldadapter",2],["settings",2],["resolvefieldadapter",2],["arrayrendernode",2],["данные",2],["описывается",2],["html",2],["тег",2],["строкой",2],["задаётся",2],["renderchild",2],["typescript",2],["ismodelfieldrendernode",2],["isarrayrendernode",2],["iscontainerrendernode",2],["ishtmltagrendernode",2],["ради",2],["заводить",2],["rounded",2],["dom",2],["null",2],["подписывается",2],["только",2],["можно",2],["важно",2],["далее",2],["patchprops",2],["как",2],["узле",2],["компоненту",2],["компоненты",2],["секция",2],["массива",2],["этом",2],["листья",2],["свойство",2],["контейнера",2],["formmodel",2],["buildschema",2],["return",2],["grid",2],["имя",2],["заголовок",2],["empty",2],["reorder",2],["selectfield",2],["coborrowers",2],["обязателен",2],["управления",2],["addbuttonlabel",2],["созаемщика",2],["emptymessage",2],["reorderable",2],["true",2],["внутри",2],["per",2],["итерирует",2],["override",2],["нужен",2],["готовые",2],["рендерится",2],["есть",2],["один",2],["modelarray",2],["пример",2],["complex",2],["multy",2],["step",2],["boolean",2],["false",2],["card",2],["компонента",2],["рендерера",2]]},{"id":"render-behavior","file":"03-render-behavior.md","title":"Render Behavior","purpose":"`RenderBehaviorFn<T>` — функция `(schema: RenderSchemaProxy<T>) => void`, навешивающая декларативное поведение на готовый `RenderSchemaProxy`. Хелперы — standalone-функции: первым аргументом принимают либо `RenderNodeControl` (узел `schema.node(\'selector\')`), либо саму схему (`renderEffect`).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Предикат `hideWhen`, не читающий сигналы реактивно** — узел не будет переоцениваться. Читай сигнал целиком (`form.x.value.value`), не сохраняй значение заранее в переменную.\\n- **`renderEffect(node, ...)` вместо `renderEffect(schema, ...)`** — первый аргумент `renderEffect` это схема, а не узел (в отличие от остальных хелперов). Node-аргумент не даст эффекта.\\n- **Подписываться на `form` напрямую внутри React-компонента вместо `renderEffect`** — теряется автоматический dispose при unmount.\\n- **Бросать исключения из `onInit`** — он синхронный и вызывается при построении схемы (до первого рендера); исключение сломает mount. Логируй и обрабатывай ошибки внутри."}],"examples":[{"lang":"tsx","code":"import { hideWhen, type RenderBehaviorFn } from \'@reformer/renderer-react\';\\n\\n// form захвачен в замыкание фабрики поведения.\\nconst behavior: RenderBehaviorFn<CreditForm> = (schema) => {\\n hideWhen(schema.node(\'mortgage-section\'), () => form.loanType.value.value !== \'mortgage\');\\n};"},{"lang":"tsx","code":"import { renderEffect } from \'@reformer/renderer-react\';\\n\\nconst wizardRef = schema.node(\'wizard\').getRef<FormWizardHandle<CreditForm>>();\\nrenderEffect(schema, () => {\\n if (form.loanType.value.value === \'mortgage\') {\\n wizardRef.current?.goToStep(1);\\n }\\n});"},{"lang":"tsx","code":"import { onComponentEvent } from \'@reformer/renderer-react\';\\n\\nonComponentEvent(schema.node(\'wizard\'), \'onSubmit\', async () => {\\n // `FormWizardProps.onSubmit` у ui-kit — это `() => void | Promise<void>`: аргументов нет,\\n // снимок берётся из модели. Типизировать как `(values: CreditForm) => …` — TS2322.\\n // Валидировать здесь руками не надо: кнопка отправки гейтит вызов через `config.validateAll`\\n // и при провале сюда не доходит (reformer://docs/cdk/multi-step-submit).\\n await submitCreditApplication(model.get());\\n});"},{"lang":"tsx","code":"import { onMount, onUnmount } from \'@reformer/renderer-react\';\\n\\nconst boundary = schema.node(\'data-boundary\');\\nonMount(boundary, () => {\\n void loadApplication(); // напр. загрузить данные и boundary.patchProps({ status: \'ready\' })\\n return () => console.log(\'cleanup\');\\n});\\nonUnmount(schema.node(\'wizard\'), () => console.log(\'wizard unmounted\'));"}],"troubleshooting":[],"seeAlso":["[02-render-schema.md](02-render-schema.md) — что такое `RenderSchemaProxy` и `schema.node(selector)`.","[05-cookbook.md](05-cookbook.md) — совмещение нескольких behavior на одном узле.","[04-troubleshooting.md](04-troubleshooting.md)."],"sections":[{"heading":"Helpers","slug":"helpers"},{"heading":"Examples","slug":"examples-2"},{"heading":"Anti-patterns","slug":"anti-patterns-2"},{"heading":"See also","slug":"see-also-3"}],"terms":[["schema",15],["node",15],["rendereffect",8],["при",7],["rendernodecontrol",6],["wizard",6],["form",6],["value",6],["узел",5],["mortgage",5],["reformer",5],["react",5],["behavior",4],["renderschemaproxy",4],["void",4],["через",4],["компонента",4],["hidewhen",4],["cleanup",4],["oncomponentevent",4],["onmount",4],["onunmount",4],["tsx",4],["import",4],["from",4],["renderer",4],["boundary",4],["render",3],["renderbehaviorfn",3],["сигналы",3],["внутри",3],["аргумент",3],["реактивно",3],["может",3],["вернуть",3],["проп",3],["onsubmit",3],["unmount",3],["loantype",3],["const",3],["creditform",3],["либо",2],["selector",2],["схему",2],["напрямую",2],["preact",2],["формы",2],["замыкание",2],["getref",2],["current",2],["первый",2],["conditionfn",2],["пока",2],["реактивный",2],["effect",2],["событие",2],["oninit",2],["синхронный",2],["вызывается",2],["mount",2],["узла",2],["section",2],["рендера",2],["wizardref",2],["что",2],["это",2],["хелперов",2],["одном",2],["узле",2],["console",2],["log",2],["вместо",2],["cookbook",2],["troubleshooting",2]]},{"id":"troubleshooting","file":"04-troubleshooting.md","title":"Troubleshooting / FAQ","purpose":"Не передан `fieldWrapper` в `settings`. Добавь:","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md)","[02-render-schema.md](02-render-schema.md)","[03-render-behavior.md](03-render-behavior.md)","[05-cookbook.md](05-cookbook.md)","[06-validation.md](06-validation.md)"],"sections":[{"heading":"Field renders without label/error","slug":"field-renders-without-label-error"},{"heading":"Field renders as null (console warning `[RenderSchema] No form node for signal ...`)","slug":"field-renders-as-null-console-warning-renderschema-no-form-node-for-signal"},{"heading":"Container children не рендерятся","slug":"container-children-ne-renderyatsya"},{"heading":"FormRenderer: render или form — что передавать","slug":"formrenderer-render-ili-form-chto-peredavat"},{"heading":"Unknown component in renderSchema","slug":"unknown-component-in-renderschema"},{"heading":"RenderSchemaProxy nodes don\'t react to behavior","slug":"renderschemaproxy-nodes-don-t-react-to-behavior"},{"heading":"Hidden node still mounts","slug":"hidden-node-still-mounts"},{"heading":"`TS2353: \'validators\' does not exist in type \'RenderNode<T>\'`","slug":"ts2353-validators-does-not-exist-in-type-rendernode-t"},{"heading":"`TS2741: Property \'__path\' is missing in type \'ModelArray<T>\' ... required in \'RenderModelArrayControl\'`","slug":"ts2741-property-path-is-missing-in-type-modelarray-t-required-in-rendermodelarraycontrol"},{"heading":"Form changes don\'t trigger re-render","slug":"form-changes-don-t-trigger-re-render"},{"heading":"Сырой контрол пишет в модель событие или течёт пропом `control` (Checkbox/Select/Radio)","slug":"syroy-kontrol-pishet-v-model-sobytie-ili-techet-propom-control-checkbox-select-radio"},{"heading":"See also","slug":"see-also-4"}],"terms":[["render",16],["value",14],["schema",12],["model",11],["form",9],["через",7],["node",7],["path",7],["children",7],["узла",7],["component",7],["settings",6],["formrenderer",6],["componentprops",6],["createform",6],["что",6],["validation",6],["контрол",6],["field",5],["поля",5],["если",5],["это",5],["control",5],["onchange",5],["fieldwrapper",4],["схемы",4],["модель",4],["рендерер",4],["проп",4],["overview",4],["react",4],["behavior",4],["hidewhen",4],["без",4],["array",4],["cookbook",4],["tsx",3],["formfield",3],["reformer",3],["для",3],["null",3],["renderschema",3],["нода",3],["сигналу",3],["реестр",3],["как",3],["сигнал",3],["лист",3],["при",3],["undefined",3],["section",3],["nodes",3],["или",3],["результат",3],["renderschemafn",3],["нет",3],["его",3],["только",3],["sethidden",3],["validators",3],["rendernode",3],["checkbox",3],["seam",3],["checked",3],["resolvefieldadapter",3],["renders",2],["передан",2],["kit",2],["warning",2],["for",2],["signal",2],["state",2],["рендера",2],["убедись",2],["внутри",2],["контейнера",2],["top",2],["level",2],["свойство",2],["title",2],["два",2],["createrenderschema",2],["bundle",2],["бандл",2],["wizard",2],["схеме",2],["раздел",2],["было",2],["верно",2],["пока",2],["unknown",2],["требует",2],["renderer",2],["don",2],["selector",2],["есть",2],["override",2],["условие",2],["type",2],["дерево",2],["modelarray",2],["rendermodelarraycontrol",2],["привязка",2],["остаётся",2],["сырой",2],["пишет",2],["событие",2],["течёт",2],["select",2],["radio",2],["based",2],["первым",2],["значение",2],["эмитит",2],["antd",2],["dom",2],["option",2],["сам",2],["адаптер",2],["valueprop",2],["fromemit",2],["tovalue",2],["контролам",2]]},{"id":"cookbook","file":"05-cookbook.md","title":"Cookbook","purpose":"Продвинутые рецепты для `@reformer/renderer-react`. Каждый рецепт — конкретный сценарий, описанный без воды: проблема, решение, ограничения.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-render-schema.md](02-render-schema.md) — структура `RenderNode` и `RenderSchemaFn`.","[03-render-behavior.md](03-render-behavior.md) — справочник по standalone-хелперам.","[04-troubleshooting.md](04-troubleshooting.md) — типичные ошибки."],"sections":[{"heading":"Custom fieldWrapper","slug":"custom-fieldwrapper"},{"heading":"Programmatic node manipulation","slug":"programmatic-node-manipulation"},{"heading":"Custom container with collapsible children","slug":"custom-container-with-collapsible-children"},{"heading":"Combining behaviors on one node","slug":"combining-behaviors-on-one-node"},{"heading":"Вся форма read-only / view-mode","slug":"vsya-forma-read-only-view-mode"},{"heading":"Презентационные блоки и живая сводка без своих компонентов","slug":"prezentatsionnye-bloki-i-zhivaya-svodka-bez-svoih-komponentov"},{"heading":"Сырой контрол сторонней UI-kit (FieldAdapter)","slug":"syroy-kontrol-storonney-ui-kit-fieldadapter"},{"heading":"See also","slug":"see-also-5"}],"terms":[["children",28],["component",23],["value",23],["reformer",22],["classname",21],["schema",21],["componentprops",18],["react",15],["control",15],["node",14],["import",13],["from",13],["section",12],["renderer",11],["form",11],["const",11],["через",10],["mortgage",10],["поля",9],["kit",9],["settings",9],["tsx",9],["formrenderer",9],["div",9],["props",9],["selector",9],["disabled",9],["wizard",9],["без",8],["testid",8],["text",8],["render",8],["notes",8],["model",8],["json",8],["onchange",8],["seam",8],["для",7],["fieldwrapper",7],["problem",7],["solution",7],["cdkformfield",7],["type",7],["нужно",7],["hidewhen",7],["уже",7],["как",7],["при",7],["значение",7],["контрол",7],["field",6],["можно",6],["return",6],["checkbox",6],["будет",6],["patchprops",6],["только",6],["title",6],["его",6],["disable",6],["fieldadapter",6],["checked",6],["cookbook",5],["label",5],["formfield",5],["wrapper",5],["если",5],["dom",5],["или",5],["например",5],["после",5],["sethidden",5],["это",5],["компонента",5],["нет",5],["behavior",5],["событие",5],["resolvefieldadapter",5],["select",5],["target",5],["fromemit",5],["каждый",4],["error",4],["сам",4],["cdk",4],["поле",4],["внутри",4],["resethidden",4],["resetprops",4],["сигналы",4],["inputfield",4],["true",4],["компонент",4],["reactnode",4],["defaultopen",4],["одном",4],["обработчик",4],["проп",4],["первый",4],["radio",4],["option",4],["arg",4],["rest",4],["tovalue",4],["strip",4],["получает",3],["fieldnode",3],["input",3],["api",3],["core",3],["fieldwrapperprops",3],["function",3],["unknown",3],["border",3],["ноды",3],["useeffect",3],["createrenderschema",3],["creditform",3],["точечно",3],["вызов",3],["условие",3],["чтобы",3],["вернуть",3],["rendernode",3],["нужен",3],["контейнер",3],["open",3],["button",3],["font",3],["схемы",3],["docs",3],["события",3],["кода",3],["принимает",3],["rendereffect",3],["oncomponentevent",3],["onmount",3],["onsubmit",3],["такой",3],["рендера",3],["oninit",3],["форма",3],["рендерер",3],["enable",3],["formfieldcontrol",3],["узла",3],["src",3],["поэтому",3],["computed",3],["blue",3],["идёт",3],["based",3],["адаптер",3],["valueprop",3],["default",3],["аргумент",3],["undefined",3],["onblur",3],["рецепт",2],["custom",2],["hint",2],["нестандартный",2],["вместо",2],["renderschema",2],["useformcontrol",2],["myfieldwrapper",2],["root",2],["data",2],["rounded",2],["small",2],["вызывается",2],["modelfieldrendernode",2],["иначе",2],["секцию",2],["менять",2],["кнопке",2],["загрузки",2],["данных",2],["proxy",2],["preact",2],["usememo",2],["мерджит",2],["повторный",2],["перекрывает",2],["реактивное",2],["контроллер",2],["моменту",2],["когда",2],["свободно",2],["usestate",2],["chevrondown",2],["chevronright",2],["containercomponentprops",2],["collapsiblesectionprops",2],["collapsiblesection",2],["setopen",2],["gap",2],["space",2],["модели",2],["false",2]]},{"id":"validation","file":"06-validation.md","title":"Validation","purpose":"Как валидировать **значения** формы, собранной из render-схемы (`@reformer/renderer-react`, M1). Всё сверено с рабочим кодом: типы узла — [types.ts](../../src/core/types.ts), исполнение над моделью — `validateModel` из `@reformer/core/validation`, рабочий пример — `complex-multy-step-form-renderer` (файл схемы там назван по-старому `render-schema.ts` — канон имени `renderer.schema.ts`) + core-каталог `complex-multy-step-form/schemas/validation.ts`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Вписывать `validators` в лист RenderNode** (`{ value: model.$.x, component: InputField, validators: [...] }`) — главная ловушка. У `ModelFieldRenderNode` нет поля `validators` (как и у array/container узлов). TypeScript даёт `TS2353: \'validators\' does not exist in type \'RenderNode<T>\'`. Валидация значений живёт в отдельной `ValidationSchema` над моделью (Шаг 1), а не в render-дереве.\\n- **Ждать, что рендерер сам провалидирует значения** — `FormRenderer` только отображает ошибки, уже проставленные в ноды. Значения проверяет `validateModel(model, schema)`; без её вызова (обычно из `validateStep`/`validateAll` wizard-а) поля не подсветятся.\\n- **Читать текущее значение вместо сигнала в `validate`** — оператор это `validate(model.$.path, [rules])`, где `model.$.path` — СИГНАЛ (стабильная ссылка на форму модели), а не текущее значение поля. Значения читает раннер в момент прогона; cross-field берёт снапшот через `model.get()` внутри `cross(sig, fn)`. Не передавайте в `validate` результат `model.get()` / `.value`.\\n- **Пересоздавать схему на каждый вызов конфига** (`validateModel(model, defineValidationSchema(...))` инлайн) — раннер отменяет **устаревший прогон той же `(model, schema)`** по ссылке на схему. Новый объект схемы на каждый вызов ломает отмену и гашение полей. Держите схемы стабильными module-level `const` (`STEP_SCHEMAS`, `fullSchema`).\\n- **Забыть `selector: \'wizard\'` при инъекции через render-behavior** — без `selector` узел не адресуется через `schema.node(\'wizard\')`, `onInit`/`patchProps` не найдут его и валидация не прокинется. (При инлайн-инъекции в `componentProps` это не нужно.)\\n- **`array` на array-узле + строгая типизация листа = `TS2741`.** Привязка массива это `array: model.<path>` (value-доступ, напр. `model.coBorrowers`), НЕ `model.$.coBorrowers`. Тип `ModelArray<U>` рантайм-совместим с требуемым `RenderModelArrayControl`, но в публичном типе у него **не объявлен** `__path`, поэтому под строгим контекстом узла TS ругается `Property \'__path\' is missing in type \'ModelArray<T>\' but required in \'RenderModelArrayControl\'`. Пример `complex-multy-step-form-renderer` обходит это кастом всего дерева `as unknown as RenderNode<T>` в конце билдера (файл схемы там назван по-старому `render-schema.ts` — канон имени `renderer.schema.ts`) — сам каст и есть канон для схемы с array-узлами; привязка при этом остаётся `array: model.<path>` (см. [02-render-schema.md](02-render-schema.md#array)). Per-item **валидация** таких массивов — оператор `each(model.<path>, im => { … })` в схеме, не в render-дереве."}],"examples":[],"troubleshooting":[],"seeAlso":["[02-render-schema.md](02-render-schema.md) — структура `RenderNode`: лист-поле несёт только layout, массивы (`array: model.<path>`).","[03-render-behavior.md](03-render-behavior.md) — `onInit`/`patchProps` для инъекции конфига в wizard-узел; `revalidateWhen`-мост к `validateModel`.","[01-overview.md](01-overview.md) — wizard-узел, `FormWizardConfig` (`{ validateStep?, validateAll? }`), передача `form` через `componentProps`.","`@reformer/core` [13-multi-step.md](../../../reformer/docs/llms/13-multi-step.md) — операторы `ValidationSchema` (`validate`/`validateAsync`/`validateWhen`/`cross`/`each`/`apply`), раннер `validateModel`, `STEP_SCHEMAS`, конфиг wizard\'а.","`@reformer/renderer-json` [06-validation.md](../../../reformer-renderer-json/docs/llms/06-validation.md) — родственный паттерн для JSON-схемы (та же model-валидация, инъекция через render-behavior)."],"sections":[{"heading":"Mental model — почему валидаторов нет в RenderNode { #mental-model }","slug":"mental-model-pochemu-validatorov-net-v-rendernode-mental-model"},{"heading":"Шаг 1 — построить схему валидации над моделью { #build-schema }","slug":"shag-1-postroit-shemu-validatsii-nad-modelyu-build-schema"},{"heading":"Шаг 2 — исполнить: `{ validateStep, validateAll }` { #execute }","slug":"shag-2-ispolnit-validatestep-validateall-execute"},{"heading":"Шаг 3 — прокинуть конфиг в wizard-узел { #inject }","slug":"shag-3-prokinut-konfig-v-wizard-uzel-inject"},{"heading":"Полный рабочий пример { #full-example }","slug":"polnyy-rabochiy-primer-full-example"},{"heading":"Anti-patterns","slug":"anti-patterns-3"},{"heading":"See also","slug":"see-also-6"}],"terms":[["model",61],["reformer",32],["render",26],["wizard",23],["schema",22],["form",21],["core",20],["import",20],["from",20],["validatemodel",17],["type",17],["step",16],["rendernode",16],["validate",16],["behavior",16],["creditform",15],["const",15],["validation",14],["renderer",14],["root",14],["componentprops",13],["validators",13],["validationschema",12],["definevalidationschema",11],["required",11],["схемы",10],["поля",10],["path",10],["валидация",10],["cross",10],["array",9],["validatestep",9],["validateall",9],["sig",9],["boolean",9],["над",8],["моделью",8],["layout",8],["component",8],["через",8],["json",8],["конфиг",8],["step_schemas",8],["types",7],["только",7],["value",7],["typescript",7],["схему",7],["узел",7],["apply",7],["formmodel",7],["promise",7],["formwizard",7],["makecreditvalidationconfig",7],["complex",6],["multy",6],["selector",6],["сам",6],["схема",6],["это",6],["email",6],["для",6],["fullschema",6],["инлайн",6],["при",6],["без",6],["oninit",6],["значения",5],["react",5],["правила",5],["валидации",5],["лист",5],["что",5],["раннер",5],["под",5],["validatewhen",5],["message",5],["loanamount",5],["контракт",5],["docs",5],["llms",5],["formwizardconfig",5],["patchprops",5],["config",5],["как",4],["формы",4],["узла",4],["пример",4],["файл",4],["там",4],["канон",4],["schemas",4],["нет",4],["несёт",4],["модели",4],["шага",4],["шаг",4],["field",4],["each",4],["min",4],["minlength",4],["step1",4],["loantype",4],["step2",4],["multi",4],["если",4],["emptyschema",4],["export",4],["function",4],["return",4],["поэтому",4],["kit",4],["overview",4],["revalidatewhen",4],["рабочий",3],["назван",3],["старому",3],["имени",3],["item",3],["сигнал",3],["который",3],["рендерер",3],["ошибки",3],["ноды",3],["валидацию",3],["void",3],["рендера",3],["rules",3],["validateasync",3],["get",3],["per",3],["композиция",3],["тип",3],["момент",3],["тот",3],["number",3],["рантайм",3],["дерева",3],["tsx",3],["formproxy",3],["узле",3],["node",3],["мост",3],["поведение",3],["revalidate",3],["defineformbehavior",3],["оператор",3],["inputfield",3],["инъекции",3],["src",2],["mental",2],["одна",2],["узлов",2],["modelfieldrendernode",2],["ts2353",2],["does",2],["not",2],["exist",2],["поле",2],["сигналу",2],["getnodeforsignal",2],["createform",2],["подсветит",2],["отображает",2],["значений",2],["отдельной",2],["прогоняет",2],["варианте",2],["jsx",2],["построить",2],["прокинуть",2],["обычная",2],["функция",2],["внутри",2],["операторы",2],["async",2],["условные",2],["ветки",2],["массивы",2],["схем",2],["max",2],["выберите",2],["кредита",2],["минимум",2],["personaldata",2],["firstname",2],["прогона",2],["readonly",2],["mortgage",2],["массивов",2],["здесь",2],["гасит",2],["той",2],["функции",2],["полная",2],["шагов",2],["makevalidationconfig",2],["инъекция",2],["принимает",2],["steps",2]]},{"id":"form-wizard","file":"07-form-wizard.md","title":"FormWizard — многошаговая форма в renderer-react","purpose":"Wizard-узел RenderSchema: `FormWizard` из `@reformer/ui-kit/form-wizard` (канонический shipped-компонент, своего визарда рендерер не поставляет). Форма передаётся через `componentProps.form`, шаги — через `componentProps.steps`, а тело шага рисуется стратегией `renderStepBody`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Форма wizard-узла","slug":"forma-wizard-uzla"},{"heading":"`renderStepBody` обязателен","slug":"renderstepbody-obyazatelen"},{"heading":"Листья внутри `steps[].body` тоже harvest\'ятся","slug":"listya-vnutri-steps-body-tozhe-harvest-yatsya"},{"heading":"Валидация и submit","slug":"validatsiya-i-submit"},{"heading":"См. также","slug":"sm-takzhe"}],"terms":[["form",14],["body",11],["wizard",9],["reformer",9],["componentprops",9],["model",8],["myform",8],["formwizard",7],["kit",7],["rendernode",7],["react",6],["component",6],["steps",5],["renderer",4],["через",4],["renderstepbody",4],["для",4],["схемы",4],["это",4],["tsx",4],["дерево",4],["buildschema",4],["formproxy",4],["schema",4],["форма",3],["компонент",3],["step",3],["formwizardconfig",3],["docs",3],["llms",3],["только",3],["render",3],["его",3],["children",3],["нужно",3],["import",3],["from",3],["inputfield",3],["без",3],["config",3],["validateall",3],["тела",3],["value",3],["стратегии",3],["нет",3],["внутри",3],["валидация",3],["validation",3],["узел",2],["рендерер",2],["шаги",2],["шага",2],["formwizardhandle",2],["под",2],["узла",2],["number",2],["title",2],["icon",2],["rendernodecomponent",2],["box",2],["при",2],["validatestep",2],["wizardform",2],["node",2],["label",2],["поэтому",2],["reactnode",2],["как",2],["child",2],["тип",2],["канон",2],["листья",2],["harvest",2],["руками",2],["submit",2],["boolean",2],["promise",2],["onsubmit",2],["void",2],["values",2],["handle",2],["behavior",2]]}],"symbols":[{"name":"ArrayComponentProps","kind":"interface","signature":"export interface ArrayComponentProps {\\n /** Отрендеренные элементы массива в порядке следования. */\\n items: ArrayItemSlot[];\\n /** Добавить элемент (значение резолвится рендерером из `initialValue` узла). */\\n onAdd(): void;\\n /** Удалить элемент по индексу. */\\n onRemove(index: number): void;\\n /** Переместить элемент (реордер). */\\n onMove(from: number, to: number): void;\\n}","summary":"Контракт компонента-рендерера массива (`{ array, item, component }` → `$component(FormArray)` / `$component(List)`): готовые элементы + мутации массива обычными колбэками.","description":"Контракт компонента-рендерера массива (`{ array, item, component }` → `$component(FormArray)`\\n/ `$component(List)`): готовые элементы + мутации массива обычными колбэками.\\n\\nКомпонент — «humble object»: он не подписывается на модель и не вызывает хуки рендерера,\\nпоэтому реализовать его может любая UI-библиотека (и протестировать на фейковых `items`\\nвообще без формы). Всё, что сверх этих полей, приходит из `componentProps` узла.","params":[],"example":"Минимальный список\\n```tsx\\nfunction MyList({ items }: ArrayComponentProps) {\\nreturn <ul>{items.map((it) => <li key={it.key}>{it.children}</li>)}</ul>;\\n}\\n```","examplesCount":1,"topics":["render-schema"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ArrayItemSlot","kind":"interface","signature":"export interface ArrayItemSlot {\\n /** Стабильный React-ключ (по идентичности под-модели элемента). */\\n key: React.Key;\\n /** Живой индекс в массиве — для `onRemove(index)` / `onMove(index, …)`. */\\n index: number;\\n /** Под-модель элемента — для меток вида `itemLabel(model, index)`. */\\n model?: unknown;\\n /** Отрендеренное поддерево элемента. */\\n children: React.ReactNode;\\n}","summary":"Один элемент массива, **уже отрендеренный** рендерером и готовый к вставке в разметку.","description":"Один элемент массива, **уже отрендеренный** рендерером и готовый к вставке в разметку.\\n\\nРендерер сам итерирует массив (подписка на структуру, кэш поддеревьев, стабильные ключи) и\\nотдаёт компоненту-рендереру массива результат — компоненту остаётся только оформление.\\nТак UI-библиотека не обязана знать ни про сигналы, ни про {@link RenderNode}, ни про хуки\\nрендерера: она получает обычные props (см. {@link ArrayComponentProps}).","params":[],"examplesCount":0,"topics":["render-schema"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ArrayRenderNode","kind":"interface","signature":"export interface ArrayRenderNode<T> extends FormSchemaNode {\\n selector?: string;\\n /** Реактивный массив модели (`model.<path>`). Расширяет базовый контракт методом `move`. */\\n array: RenderModelArrayControl;\\n /**\\n * Компонент-рендерер массива (из `$component(...)`): секция с add/remove/reorder либо\\n * chrome-less список. Итерирует **рендерер**, а компонент получает результат обычными props —\\n * {@link ArrayComponentProps} (`items` + `onAdd`/`onRemove`/`onMove`) плюс `componentProps` узла.\\n *\\n * Без `component` узел рендерится безхромным fallback\'ом (только элементы, без кнопок) —\\n * зарегистрируй `FormArray` из `@reformer/ui-kit` или свой компонент, если нужен UI управления.\\n */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n component?: ComponentType<any>;\\n /** Схема элемента: под-модель элемента → узел поддерева. */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n item: (itemModel: any) => RenderNode<T>;\\n /**\\n * Значение нового элемента для кнопки «Добавить»: значение или фабрика `() => value`.\\n * `unknown | (() => …)` схлопывается в `unknown`; вариант выбирается в рантайме по\\n * `typeof === \'function\'`. (Параметризовать по `T` нельзя: `T` здесь — payload\\n * `RenderNode<T>`, а не тип данных элемента.)\\n */\\n initialValue?: unknown;\\n /** Оформление секции массива. */\\n componentProps?: {\\n title?: string;\\n addButtonLabel?: string;\\n removeButtonLabel?: string;\\n emptyMessage?: string;\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n itemLabel?: string | ((itemModel: any, index: number) => string);\\n className?: string;\\n cardClassName?: string;\\n /** Показывать кнопки ↑/↓ перестановки элементов. По умолчанию `false`. */\\n reorderable?: boolean;\\n [key: string]: unknown;\\n };\\n}","summary":"Узел-массив единой схемы (M1): данные принадлежат модели (`array`), форма элемента описывается `item(itemModel)`.","description":"Узел-массив единой схемы (M1): данные принадлежат модели (`array`), форма элемента описывается\\n`item(itemModel)`. `createForm` материализует `ModelArrayNode` (по `{ array, item }`), рендерер\\nитерирует элементы и рисует поддерево `item(itemModel)` (листья на сигналах под-модели).","params":[],"example":"```typescript\\n{ array: model.coBorrowers, initialValue: createBlankCoBorrower,\\n item: (im) => ({ component: Box, children: [{ value: im.$.phone, component: InputField }] }) }\\n```","examplesCount":1,"topics":["overview","render-schema","troubleshooting","validation"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ContainerComponentProps","kind":"interface","signature":"export interface ContainerComponentProps {\\n /** CSS класс */\\n className?: string;\\n\\n /** Дочерние элементы (рендерятся FormRenderer) */\\n children?: React.ReactNode;\\n\\n /** Произвольные дополнительные props */\\n [key: string]: unknown;\\n}","summary":"**Runtime-props** компонента-контейнера: то, что компонент получает при рендере (с уже отрисованными `children`).","description":"**Runtime-props** компонента-контейнера: то, что компонент получает при рендере (с уже\\nотрисованными `children`). Не путать с {@link ContainerRenderNodeProps} — тот описывает\\nдекларативный `componentProps` контейнера в узле схемы (без `children`).","params":[],"examplesCount":0,"topics":["cookbook"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ContainerRenderNode","kind":"interface","signature":"export interface ContainerRenderNode<T> extends FormSchemaNode {\\n /**\\n * Идентификатор узла — используется составными компонентами (wizard, tabs)\\n * и renderBehavior (b.hideWhen).\\n */\\n selector?: string;\\n\\n /**\\n * React-компонент контейнера либо нативный HTML-тег строкой (`\'div\'`, `\'section\'`, `\'p\'`).\\n * В рендере обязателен. Для тега `componentProps` — это DOM-атрибуты (`className`, `id`,\\n * `aria-*`), а `selector` в DOM НЕ пробрасывается (он адресует узел, а не элемент).\\n */\\n component: ElementType;\\n\\n /**\\n * Содержимое узла: вложенные узлы и текстовые части ({@link RenderChild}) в любом порядке.\\n * Текст — литерал, число или сигнал модели; подряд идущие части склеиваются без разделителя,\\n * а сигнал подписывается точечно (перерисовывается только текст, а не поддерево).\\n * Void-теги (`hr`, `br`, `img`) содержимого не имеют — `children` для них игнорируются.\\n */\\n children?: RenderChild<T>[];\\n\\n /** Props для компонента-контейнера (className, title и т.д.) */\\n componentProps?: ContainerRenderNodeProps;\\n}","summary":"Узел контейнера (Box, Section, Collapsible и т.д.) либо нативной HTML-вёрстки (`\'div\'`, `\'p\'`, `\'h3\'`, `\'hr\'`) — они различаются только типом `component` и рендерятся одной веткой.","description":"Узел контейнера (Box, Section, Collapsible и т.д.) либо нативной HTML-вёрстки (`\'div\'`, `\'p\'`,\\n`\'h3\'`, `\'hr\'`) — они различаются только типом `component` и рендерятся одной веткой.\\n\\n**Важно:** `children` — это TOP-LEVEL свойство узла, НЕ часть `componentProps`.\\nЕсли положить `children` внутрь `componentProps`, то `node.children` будет undefined\\nи рендерер ничего не отрисует (он деструктурирует `const { children } = node`).","params":[],"example":"Контейнер-компонент\\n```typescript\\n{\\ncomponent: Section,\\ncomponentProps: {\\ntitle: \'Личные данные\',\\nclassName: \'grid grid-cols-2 gap-4\',\\n},\\nchildren: [\\n{ value: model.$.firstName, component: InputField },\\n{ value: model.$.lastName, component: InputField },\\n],\\n}\\n```","examplesCount":2,"topics":["overview","render-schema","validation"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ContainerRenderNodeProps","kind":"interface","signature":"export interface ContainerRenderNodeProps {\\n /** CSS класс для контейнера */\\n className?: string;\\n\\n /** Произвольные props для компонента контейнера */\\n [key: string]: unknown;\\n}","summary":"Props контейнера **в узле схемы** (`ContainerRenderNode.componentProps`) — декларативный конфиг.","description":"Props контейнера **в узле схемы** (`ContainerRenderNode.componentProps`) — декларативный конфиг.\\nДочерние узлы задаются через `ContainerRenderNode.children`, а не здесь; `children` тут нет.\\n\\nНе путать с {@link ContainerComponentProps} — тот описывает **runtime-props**, которые\\nкомпонент-контейнер получает при рендере (уже с отрисованными `children: ReactNode`).","params":[],"examplesCount":0,"topics":["form-wizard"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"createReactForm","kind":"function","signature":"export function createReactForm<T extends object>(config: CreateReactFormConfig<T>): ReactForm<T>","summary":"Собрать модель, форму, валидацию и рендер-схему за один проход.","description":"Собрать модель, форму, валидацию и рендер-схему за один проход.","params":[["config","- {@link CreateReactFormConfig}: (`initial` | `model`) + `schema` + опц.\\n`behavior`, `validation`, `renderBehavior`, `seed`, `setup`."]],"returns":"","example":"```tsx\\nconst credit = useReactForm(() =>\\n createReactForm<CreditForm>({\\n model: createCreditModel(),\\n schema: buildCreditSchema, // (model, form?) => RenderNode<CreditForm>\\n behavior: creditBehavior,\\n validation: { steps: { loan: loanRules }, extras: crossRules },\\n renderBehavior: makeCreditRenderBehavior,\\n })\\n);\\nreturn <FormRenderer form={credit} settings={{ fieldWrapper: FormField }} />;\\n```","examplesCount":1,"topics":["overview","troubleshooting","form-wizard"],"sourcePath":"src/create-react-form.ts","entries":["."],"package":"@reformer/renderer-react","usage":8},{"name":"CreateReactFormConfig","kind":"interface","signature":"export interface CreateReactFormConfig<T> extends CreateFormConfigBase<T, ReactForm<T>> {\\n /**\\n * Билдер дерева. Вызывается ДВАЖДЫ: сперва без `form` (это дерево уходит в `createForm`), затем\\n * с `form` — для рендера. Узлы, которым нужна форма (визард), берут её из второго аргумента.\\n */\\n schema: (model: FormModel<T>, form?: FormProxy<T>) => RenderNode<T>;\\n /** Фабрика render-behavior: получает уже собранные форму, модель и валидацию. */\\n renderBehavior?: (\\n form: FormProxy<T>,\\n model: FormModel<T>,\\n validation?: FormValidationBundle<T>\\n ) => RenderBehaviorFn<T>;\\n}","summary":"Конфиг {@link createReactForm}.","description":"Конфиг {@link createReactForm}.","params":[],"examplesCount":0,"sourcePath":"src/create-react-form.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"createRenderSchema","kind":"function","signature":"export function createRenderSchema<T>(fn: RenderSchemaFn<T>): RenderSchemaProxy<T>","summary":"Оборачивает {@link RenderSchemaFn} в {@link RenderSchemaProxy} — функцию-схему с дополнительным API `.node(selector)` для императивного управления нодами (видимость, `componentProps`, ref) и точкой применения декларативного поведения (`hideWhen`/`renderEffect`/`onComponentEvent`/lifecycle-хуки).","description":"Оборачивает {@link RenderSchemaFn} в {@link RenderSchemaProxy} — функцию-схему\\nс дополнительным API `.node(selector)` для императивного управления нодами\\n(видимость, `componentProps`, ref) и точкой применения декларативного поведения\\n(`hideWhen`/`renderEffect`/`onComponentEvent`/lifecycle-хуки).\\n\\nВозвращённый прокси остаётся вызываемой `RenderSchemaFn`, поэтому его напрямую\\nпередают в `render` у {@link FormRenderer}. Переопределения хранятся в Map-ах и\\nприменяются реактивно (через версионный сигнал) — перерисовывается только затронутая нода.","params":[["fn","- Исходная функция-схема (без аргументов; привязка к данным — через сигналы в листьях)"]],"returns":"","example":"Программное управление нодами\\n```tsx\\nconst schema = createRenderSchema<MyForm>(() => ({\\nselector: \'root\',\\ncomponent: Box,\\nchildren: [\\n{ selector: \'extra-section\', component: Section, componentProps: { title: \'Доп.\' } },\\n],\\n}));\\n\\nschema.node(\'extra-section\').setHidden(true);\\nschema.node(\'extra-section\').patchProps({ title: \'Новый заголовок\' });\\nschema.node(\'extra-section\').resetHidden();\\n\\n<FormRenderer render={schema} />\\n```","examplesCount":1,"topics":["overview","render-schema","troubleshooting","cookbook"],"sourcePath":"src/core/render-schema-proxy.ts","entries":["."],"package":"@reformer/renderer-react","usage":2},{"name":"FieldAdapter","kind":"interface","signature":"export interface FieldAdapter {\\n /** Проп, из которого контрол читает значение (default `\'value\'`). */\\n valueProp?: string;\\n /** Колбэк, через который контрол эмитит изменение (default `\'onChange\'`). */\\n changeProp?: string;\\n /**\\n * emit контрола → значение поля (default — как есть). `rest` — прочие props контрола\\n * (например, чтобы достать `options` при резолве значения).\\n */\\n fromEmit?: (arg: unknown, rest: Record<string, unknown>) => unknown;\\n /** значение поля → `valueProp` контрола (coerce `null`/`undefined`; default — как есть). */\\n toValue?: (value: unknown) => unknown;\\n /** Проброс blur нестандартным каналом (default — прокидывается `onBlur`). */\\n bindBlur?: (onBlur: () => void) => Record<string, unknown>;\\n /** Ключи, которые убрать из `componentProps` перед спредом в контрол. */\\n strip?: string[];\\n /**\\n * Передавать ли контролу ноду формы пропом `control` (§3.1). По умолчанию `false`: `control`\\n * контролу не нужен (реактивные пропы мёржит рендерер, errors/touched — FieldWrapper). Ставь\\n * `true`, если контрол сам потребляет ноду (напр. вызывает `useFormControl(control)`). Альтернатива\\n * без адаптера — статик на компоненте: `MyControl.reformerNeedsControl = true`.\\n */\\n passControl?: boolean;\\n}","summary":"Адаптер поля: как свести value-based seam рендерера (`value` + `onChange(value)`) к контракту конкретного контрола библиотеки.","description":"Адаптер поля: как свести value-based seam рендерера (`value` + `onChange(value)`) к контракту\\nконкретного контрола библиотеки. Резолвится через {@link RendererSettings.resolveFieldAdapter}\\nпо компоненту поля (`node.component`). Позволяет регистрировать СЫРЫЕ контролы любого UI-kit —\\nрендерер сам переложит seam на их диалект (`checked` + `onChange(event)`, `value` + `(value, option)`\\nи т.д.). Нет адаптера → контрол получает seam как есть (текущее поведение, обратная совместимость).","params":[],"example":"Checkbox (значение в `checked`, эмитит DOM-событие)\\n```ts\\n{ valueProp: \'checked\', fromEmit: (e) => (e as any).target.checked, toValue: (v) => v ?? false }\\n```","examplesCount":1,"topics":["overview","render-schema","troubleshooting","cookbook"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"FieldWrapperProps","kind":"interface","signature":"export interface FieldWrapperProps {\\n /** Контрол поля */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n control: any;\\n /** CSS класс */\\n className?: string;\\n /** Дочерний элемент (отрендеренный input) */\\n children: React.ReactNode;\\n /**\\n * testId для генерации data-testid на wrapper/label/error.\\n * Выводится рендерером из пути сигнала (`model.$.<path>`, точки → дефисы)\\n * или переопределяется через `componentProps.testId`.\\n */\\n testId?: string;\\n}","summary":"Props для компонента-обёртки поля Обёртка получает control и рендерит label, input и errors.","description":"Props для компонента-обёртки поля\\n\\nОбёртка получает control и рендерит label, input и errors.","params":[],"examplesCount":0,"topics":["cookbook"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"FormRenderer","kind":"function","signature":"export function FormRenderer<T>({ render, form, settings }: FormRendererProps<T>): ReactNode","summary":"Рендеринг формы по {@link RenderSchemaFn} или {@link RenderSchemaProxy}.","description":"Рендеринг формы по {@link RenderSchemaFn} или {@link RenderSchemaProxy}.\\n\\nПринимает `render` — функцию-схему (или обёртку из {@link createRenderSchema})\\nи опциональные `settings` (например, глобальный `fieldWrapper`). Разворачивает\\nкорневой узел и рекурсивно рендерит дерево через {@link RenderNodeComponent}.\\nЕсли `render` — прокси, дополнительно монтирует реактивные эффекты (`renderEffect`)\\nи прокидывает карты переопределений (`setHidden`/`patchProps`/`hideWhen`) через контекст.\\n\\nСхему берёт либо из пропа `render`, либо из бандла `form` ({@link createReactForm}) — явный проп\\nважнее. Саму форму (для wizard-узла) в дерево доносит билдер схемы или render-behavior, а не\\nотдельный проп рендерера.","params":[["props","- {@link FormRendererProps}: `render` либо `form`, плюс опц. `settings`"]],"returns":"React-дерево формы","example":"Сборка и рендер одним вызовом\\n```tsx\\nimport { FormRenderer, createReactForm, useReactForm } from \'@reformer/renderer-react\';\\nimport { FormField } from \'@reformer/ui-kit\';\\n\\nconst myForm = useReactForm(() =>\\ncreateReactForm<MyForm>({\\nmodel: createMyModel(),\\nschema: buildSchema, // (model, form?) => RenderNode<MyForm>\\nbehavior: myFormBehavior,\\nvalidation: myValidation,\\nrenderBehavior: makeMyRenderBehavior,\\n})\\n);\\n\\n<FormRenderer form={myForm} settings={{ fieldWrapper: FormField }} />\\n```","examplesCount":1,"topics":["overview","render-schema","render-behavior","troubleshooting","cookbook","validation"],"sourcePath":"src/core/form-renderer.tsx","entries":["."],"package":"@reformer/renderer-react","usage":8},{"name":"FormRendererProps","kind":"interface","signature":"export interface FormRendererProps<T> {\\n /**\\n * Функция создания RenderSchema (или RenderSchemaProxy из createRenderSchema).\\n * Опционален, если задан `form`.\\n */\\n render?: RenderSchemaFn<T>;\\n\\n /**\\n * Бандл `createReactForm` — поставляет схему (`form.render`), поэтому `render` передавать не\\n * нужно. Тип структурный намеренно: слой типов рендерера не зависит от фабрики.\\n *\\n * Приоритет: явный `render` → `form.render`.\\n */\\n form?: { render: RenderSchemaFn<T> };\\n\\n /**\\n * Настройки рендерера\\n *\\n * @example\\n * ```tsx\\n * <FormRenderer form={myForm} settings={{ fieldWrapper: FormField }} />\\n * ```\\n */\\n settings?: RendererSettings;\\n}","summary":"Props для FormRenderer","description":"Props для FormRenderer","params":[],"examplesCount":0,"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"hideWhen","kind":"function","signature":"export function hideWhen(node: RenderNodeControl, conditionFn: () => boolean): void","summary":"Объявить условие скрытия для ноды.","description":"Объявить условие скрытия для ноды.\\n\\nУсловие реактивно — пересчитывается при изменении любого Preact-сигнала,\\nпрочитанного внутри conditionFn (в т.ч. сигналов формы через ref).","params":[],"example":"```typescript\\nconst wizardRef = schema.node(\'wizard\').getRef<FormWizardHandle<MyForm>>();\\nhideWhen(schema.node(\'mortgage-section\'), () =>\\n wizardRef.current?.form.loanType.value.value !== \'mortgage\'\\n);\\n```","examplesCount":1,"topics":["overview","render-schema","render-behavior","troubleshooting","cookbook","form-wizard"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":12},{"name":"isArrayRenderNode","kind":"function","signature":"export function isArrayRenderNode<T>(node: RenderNode<T>): node is ArrayRenderNode<T>","summary":"Type guard для {@link ArrayRenderNode} (M1): массив модели `{ array, item }`.","description":"Type guard для {@link ArrayRenderNode} (M1): массив модели `{ array, item }`.\\nПроверяется до контейнера (у array-узла нет `component`).","params":[["node","- Узел {@link RenderNode}"]],"returns":"`true`, если узел — секция массива (есть `array` и `item`-фабрика)","example":"Сужение к массиву\\n```typescript\\nif (isArrayRenderNode(node)) {\\nnode.array; // реактивный массив модели\\nnode.item; // (itemModel) => RenderNode поддерева элемента\\n}\\n```","examplesCount":1,"topics":["overview","render-schema"],"sourcePath":"src/core/utils.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"isContainerRenderNode","kind":"function","signature":"export function isContainerRenderNode<T>(node: RenderNode<T>): node is ContainerRenderNode<T>","summary":"Type guard для ContainerRenderNode Проверяет, что узел является контейнером (Box, Section, `\'div\'` и т.д.).","description":"Type guard для ContainerRenderNode\\n\\nПроверяет, что узел является контейнером (Box, Section, `\'div\'` и т.д.).\\n\\nПринимает любой валидный React element type:\\n- plain function component (`function Foo() {...}`),\\n- `React.memo(...)` / `React.forwardRef(...)` обёртки (объекты с `$$typeof`),\\n- lazy / context provider\'ы / прочие React-внутренности,\\n- строку нативного HTML-тега (`\'div\'`, `\'p\'`) — см. {@link isHtmlTagRenderNode}.","params":[],"example":"```typescript\\nif (isContainerRenderNode(node)) {\\n // node.component - React component или строка-тег\\n // node.children - дочерние узлы\\n}\\n```","examplesCount":1,"topics":["overview","render-schema"],"sourcePath":"src/core/utils.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"isHtmlTagRenderNode","kind":"function","signature":"export function isHtmlTagRenderNode<T>(node: RenderNode<T>): node is ContainerRenderNode<T>","summary":"Type guard: узел — нативный HTML-тег (`component` задан строкой), а не React-компонент.","description":"Type guard: узел — нативный HTML-тег (`component` задан строкой), а не React-компонент.\\nРендерер различает их, чтобы не пробрасывать `selector` в DOM-атрибуты и не передавать\\nсодержимое void-тегам.","params":[["node","- Узел {@link RenderNode}"]],"returns":"`true`, если `node.component` — строка-тег","example":"```typescript\\nisHtmlTagRenderNode({ component: \'div\' }); // true\\nisHtmlTagRenderNode({ component: Section }); // false\\n```","examplesCount":1,"topics":["render-schema"],"sourcePath":"src/core/utils.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"isModelFieldRenderNode","kind":"function","signature":"export function isModelFieldRenderNode<T>(node: RenderNode<T>): node is ModelFieldRenderNode","summary":"Type guard для {@link ModelFieldRenderNode} (M1): лист, привязанный к сигналу модели.","description":"Type guard для {@link ModelFieldRenderNode} (M1): лист, привязанный к сигналу модели.\\nПроверяется ПЕРВЫМ — такой узел несёт реальный `component`, иначе спутается с контейнером.","params":[["node","- Узел {@link RenderNode}"]],"returns":"`true`, если узел — поле-лист (`value instanceof Signal`)","example":"Сужение к полю\\n```typescript\\nif (isModelFieldRenderNode(node)) {\\nnode.value; // Signal модели\\nnode.component; // UI-компонент поля\\n}\\n```","examplesCount":1,"topics":["overview","render-schema"],"sourcePath":"src/core/utils.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"isRenderSchemaProxy","kind":"function","signature":"export function isRenderSchemaProxy<T>(fn: RenderSchemaFn<T>): fn is RenderSchemaProxy<T>","summary":"Type guard: проверяет, что `fn` — это результат {@link createRenderSchema}.","description":"Type guard: проверяет, что `fn` — это результат {@link createRenderSchema}.","params":[["fn","- Произвольная `RenderSchemaFn`."]],"returns":"`true`, если `fn` обёрнута через `createRenderSchema`.","example":"```typescript\\nimport { isRenderSchemaProxy, createRenderSchema } from \'@reformer/renderer-react\';\\n\\nconst proxy = createRenderSchema(renderSchemaFn);\\nisRenderSchemaProxy(proxy); // true\\nisRenderSchemaProxy(renderSchemaFn); // false\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/core/render-schema-proxy.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"ModelFieldRenderNode","kind":"interface","signature":"export interface ModelFieldRenderNode extends FormSchemaNode {\\n selector?: string;\\n /** Сигнал значения из модели (`model.$.<path>`). */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n value: Signal<any>;\\n /** UI-компонент поля (в рендере обязателен, в отличие от базового {@link FormSchemaNode}). */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n component: ComponentType<any>;\\n /** Props компонента (+ опц. `testId`/`className`/`fieldWrapper`/`wrapper`). */\\n componentProps?: Record<string, unknown> & {\\n testId?: string;\\n className?: string;\\n fieldWrapper?: ComponentType<FieldWrapperProps>;\\n wrapper?: ElementType;\\n };\\n}","summary":"Узел-поле единой схемы (M1): значение приходит из СИГНАЛА модели (`model.$.x`), `component` + `componentProps` — конфиг поля (как в схеме формы).","description":"Узел-поле единой схемы (M1): значение приходит из СИГНАЛА модели (`model.$.x`),\\n`component` + `componentProps` — конфиг поля (как в схеме формы). State-нода (errors/disabled)\\nрезолвится по сигналу через реестр сигнал→нода (заполняется `createForm`).","params":[],"example":"```typescript\\n{ value: model.$.loanType, component: SelectField, componentProps: { label: \'Тип\', options } }\\n```","examplesCount":1,"topics":["overview","render-schema","cookbook","validation"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"NodeLifecycleHooks","kind":"interface","signature":"export interface NodeLifecycleHooks {\\n /** Срабатывает один раз при mount ноды. Может вернуть cleanup-функцию. */\\n onMount?: () => void | (() => void);\\n /** Срабатывает один раз при unmount ноды. */\\n onUnmount?: () => void;\\n}","summary":"Хуки жизненного цикла ноды, регистрируемые через render-behavior.","description":"Хуки жизненного цикла ноды, регистрируемые через render-behavior.\\nКаждый хук опционален; повторная регистрация перезаписывает предыдущее значение.","params":[],"examplesCount":0,"sourcePath":"src/core/render-schema-proxy.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"onComponentEvent","kind":"function","signature":"export function onComponentEvent(\\n node: RenderNodeControl,\\n event: string,\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n handler: (...args: any[]) => any\\n): void","summary":"Зарегистрировать колбэк на проп-событие компонента.","description":"Зарегистрировать колбэк на проп-событие компонента.\\n\\nПозволяет объявить обработчики (onSubmit, onChange и т.п.) в behavior\\nвместо жёсткого указания в componentProps схемы.\\nКолбэк получает ровно те же аргументы, что и оригинальный проп компонента.","params":[],"example":"```typescript\\nonComponentEvent(schema.node(\'region\'), \'onChange\', (value: string) => {\\n loadCities(value);\\n});\\n```\\n\\nДля отправки формы этот механизм не нужен: кнопка мастера сама гейтит вызов через\\n`config.validateAll`, поэтому обработчик отправки передаётся пропом `onSubmit`\\n(см. `reformer://docs/cdk/multi-step-submit`). Подписка на `\'onSubmit\'` в обход\\nэтого гейта — анти-паттерн: она вызывается по клику, до валидации.","examplesCount":1,"topics":["overview","render-behavior","cookbook","validation","form-wizard"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":10},{"name":"onInit","kind":"function","signature":"export function onInit(_node: RenderNodeControl, fn: () => void): void","summary":"Синхронный build-time hook.","description":"Синхронный build-time hook. Вызывается один раз при применении behavior к схеме\\n(до первого рендера ноды). Это единственный хук, способный повлиять на первый\\nрендер — внутри можно дергать `schema.node(selector).patchProps({ ... })`\\nдля установки/обновления componentProps.\\n\\nТипичный кейс: создать форму/стейт, закрепить за нодой через patchProps.\\n\\nВ ОТЛИЧИЕ от {@link onMount}/{@link onUnmount} это НЕ пер-нодовый lifecycle-хук: он не\\nпривязан к монтированию какой-либо ноды и не хранится в lifecycleRegistry. Аргумент `_node`\\nпринимается только ради симметрии сигнатуры с onMount/onUnmount и не используется — `fn`\\nвызывается синхронно в момент применения behavior к схеме.","params":[],"example":"```typescript\\nonInit(schema.node(\'wizard\'), () => {\\n const form = createMyForm();\\n schema.node(\'wizard\').patchProps({ form });\\n});\\n```","examplesCount":1,"topics":["overview","render-behavior","cookbook","validation"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":15},{"name":"onMount","kind":"function","signature":"export function onMount(node: RenderNodeControl, fn: () => void | (() => void)): void","summary":"Post-mount hook.","description":"Post-mount hook. Срабатывает после первого mount ноды (через useEffect).\\nМожет вернуть cleanup, который выполнится при unmount.","params":[],"example":"```typescript\\nonMount(schema.node(\'wizard\'), () => {\\n console.log(\'wizard mounted\');\\n return () => console.log(\'wizard cleanup from onMount\');\\n});\\n```","examplesCount":1,"topics":["overview","render-behavior","cookbook"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":5},{"name":"onUnmount","kind":"function","signature":"export function onUnmount(node: RenderNodeControl, fn: () => void): void","summary":"Pre-unmount hook.","description":"Pre-unmount hook. Срабатывает при unmount ноды.","params":[],"example":"```typescript\\nonUnmount(schema.node(\'wizard\'), () => {\\n console.log(\'wizard unmounted\');\\n});\\n```","examplesCount":1,"topics":["overview","render-behavior"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":3},{"name":"ReactForm","kind":"interface","signature":"export interface ReactForm<T> extends CoreForm<T> {\\n /** Схема для `<FormRenderer form={…} />` — с уже наложенным render-behavior. */\\n render: RenderSchemaProxy<T>;\\n}","summary":"Результат {@link createReactForm}: бандл `createCoreForm` + готовая к рендеру схема.","description":"Результат {@link createReactForm}: бандл `createCoreForm` + готовая к рендеру схема.","params":[],"examplesCount":0,"sourcePath":"src/create-react-form.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderBehaviorFn","kind":"type","signature":"export type RenderBehaviorFn<T> = (schema: RenderSchemaProxy<T>) => void;","summary":"Функция-схема поведения рендера.","description":"Функция-схема поведения рендера.\\nАналог BehaviorSchemaFn из","params":[],"example":"```typescript\\nconst behavior: RenderBehaviorFn<MyForm> = (schema) => {\\nconst wizardRef = schema.node(\'wizard\').getRef<FormWizardHandle<MyForm>>();\\n\\nhideWhen(schema.node(\'mortgage-section\'), () =>\\nwizardRef.current?.form.loanType.value.value !== \'mortgage\'\\n);\\n\\nrenderEffect(schema, () => {\\nconst form = wizardRef.current?.form;\\nif (form?.loanType.value.value === \'mortgage\') {\\nwizardRef.current?.goToStep(1);\\n}\\n});\\n};\\n```","examplesCount":1,"topics":["overview","render-behavior","cookbook","validation"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":8},{"name":"RenderChild","kind":"type","signature":"export type RenderChild<T> = RenderNode<T> | RenderTextPart;","summary":"Ребёнок контейнера: вложенный узел ЛИБО текстовая часть.","description":"Ребёнок контейнера: вложенный узел ЛИБО текстовая часть. Текст — такой же ребёнок, как узел,\\nпоэтому его можно ставить в любую позицию (в том числе ПОСЛЕ вложенного узла), а подряд идущие\\nчасти склеиваются без разделителя.","params":[],"example":"```typescript\\n{ component: \'h3\', children: [\'Итого\'] }\\n{ component: \'p\', children: [\'Платёж: \', model.$.monthlyPayment, \' ₽\'] }\\n{ component: \'p\', children: [{ component: \'b\', children: [\'Важно:\'] }, \' и далее текст\'] }\\n```","examplesCount":1,"topics":["render-schema"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderContextProvider","kind":"function","signature":"export function RenderContextProvider<T>({\\n value,\\n children,\\n}: {\\n value: RenderContextValue<T>;\\n children: ReactNode;\\n}): ReactNode","summary":"Provider для контекста рендеринга.","description":"Provider для контекста рендеринга. Снабжает дочерние компоненты текущей формой\\nи настройками (`settings`). Обычно создаётся {@link FormRenderer} автоматически — явно\\nнужен только при ручном построении дерева через {@link RenderNodeComponent}.","params":[],"example":"```tsx\\nimport { RenderContextProvider, RenderNodeComponent } from \'@reformer/renderer-react\';\\n\\n<RenderContextProvider value={{ form, settings: { fieldWrapper } }}>\\n <RenderNodeComponent node={rootNode} />\\n</RenderContextProvider>\\n```","examplesCount":1,"topics":["overview","form-wizard"],"sourcePath":"src/core/render-context.tsx","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderContextValue","kind":"interface","signature":"export interface RenderContextValue<T = unknown> {\\n /** Proxy формы (опционально — может быть предоставлена wizard-компонентом через props) */\\n form?: FormProxy<T>;\\n /** Настройки рендерера */\\n settings?: RendererSettings;\\n}","summary":"Значение контекста рендеринга","description":"Значение контекста рендеринга","params":[],"examplesCount":0,"sourcePath":"src/core/render-context.tsx","entries":["."],"package":"@reformer/renderer-react"},{"name":"renderEffect","kind":"function","signature":"export function renderEffect<T>(\\n schema: RenderSchemaProxy<T>,\\n effectFn: () => void | (() => void)\\n): void","summary":"Зарегистрировать реактивный side-effect.","description":"Зарегистрировать реактивный side-effect.\\n\\neffectFn оборачивается в Preact effect() — автоматически перезапускается\\nпри изменении любого сигнала, прочитанного внутри effectFn.\\nМожет вернуть функцию очистки.","params":[],"example":"```typescript\\nconst wizardRef = schema.node(\'wizard\').getRef<FormWizardHandle<MyForm>>();\\nrenderEffect(schema, () => {\\n const form = wizardRef.current?.form;\\n if (form?.loanType.value.value === \'mortgage\') {\\n wizardRef.current?.goToStep(1);\\n }\\n});\\n```","examplesCount":1,"topics":["overview","render-schema","render-behavior","troubleshooting","cookbook","validation","form-wizard"],"sourcePath":"src/core/render-behavior.ts","entries":["."],"package":"@reformer/renderer-react","usage":3},{"name":"RendererSettings","kind":"interface","signature":"export interface RendererSettings {\\n /**\\n * Компонент-обёртка для полей (опционально)\\n *\\n * Если указан, каждое поле будет обёрнуто этим компонентом.\\n * Обёртка отвечает за рендеринг label, errors и т.д.\\n */\\n fieldWrapper?: React.ComponentType<FieldWrapperProps>;\\n /**\\n * Резолв {@link FieldAdapter} по компоненту поля (`node.component`). Возвращает адаптер для\\n * контролов с нестандартным диалектом (Checkbox/Select/Radio) либо `undefined` — тогда seam\\n * применяется как есть. Позволяет подключать сырые компоненты любого UI-kit, не оборачивая\\n * каждый контрол. Ядро при этом остаётся UI-агностичным (адаптер — данные приложения).\\n */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n resolveFieldAdapter?: (component: React.ComponentType<any>) => FieldAdapter | undefined;\\n}","summary":"Настройки рендерера формы","description":"Настройки рендерера формы","params":[],"examplesCount":0,"topics":["cookbook"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderModelArrayControl","kind":"interface","signature":"export interface RenderModelArrayControl extends SchemaArrayControl {\\n /** Переместить элемент (реордер; runtime-фасад модель-массива это уже умеет). */\\n move(from: number, to: number): void;\\n}","summary":"Контракт реактивного массива модели для рендера: базовый {@link SchemaArrayControl} (`__path`/`length`/`at`/`push`/`removeAt`) + `move` для реордера.","description":"Контракт реактивного массива модели для рендера: базовый {@link SchemaArrayControl}\\n(`__path`/`length`/`at`/`push`/`removeAt`) + `move` для реордера.","params":[],"examplesCount":0,"topics":["render-schema","troubleshooting","validation"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderNode","kind":"type","signature":"export type RenderNode<T> = ModelFieldRenderNode | ArrayRenderNode<T> | ContainerRenderNode<T>;","summary":"Узел рендеринга формы Дискриминированный union из типов узлов: - ModelFieldRenderNode — поле формы, привязанное к СИГНАЛУ модели (M1, единая схема) - ArrayRenderNode — массив модели (M1): данные `{ array, item }`, рендер-секция - ContainerRenderNode — контейнер (Box, Section, wizard и т.д.)","description":"Узел рендеринга формы\\n\\nДискриминированный union из типов узлов:\\n- ModelFieldRenderNode — поле формы, привязанное к СИГНАЛУ модели (M1, единая схема)\\n- ArrayRenderNode — массив модели (M1): данные `{ array, item }`, рендер-секция\\n- ContainerRenderNode — контейнер (Box, Section, wizard и т.д.)","params":[],"examplesCount":0,"topics":["overview","render-schema","troubleshooting","cookbook","validation","form-wizard"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react","usage":8},{"name":"RenderNodeComponent","kind":"function","signature":"export function RenderNodeComponent<T>({\\n node,\\n form,\\n fieldWrapper: fieldWrapperProp,\\n}: RenderNodeComponentProps<T>): ReactNode","summary":"Рекурсивный рендеринг узла {@link RenderNode}.","description":"Рекурсивный рендеринг узла {@link RenderNode}. Определяет тип узла и рендерит\\nсоответственно: {@link ModelFieldRenderNode} → компонент поля с wrapper (значение\\nиз сигнала модели, state — по сигналу через реестр), {@link ArrayRenderNode} → секция\\nмассива модели, {@link ContainerRenderNode} → контейнер с дочерними узлами. Учитывает\\n`hideWhen`/`setHidden`, `patchProps`, `onComponentEvent`, lifecycle-хуки и ref из\\n{@link RenderSchemaProxy}. Обычно вызывается {@link FormRenderer}; явный вызов нужен\\nпри ручной композиции.","params":[["props","- `node` (узел), опц. `form` и `fieldWrapper`"]],"returns":"Отрендеренное поддерево или `null` (если узел скрыт / нет ноды для сигнала)","example":"```tsx\\nimport { RenderNodeComponent } from \'@reformer/renderer-react\';\\n\\n<RenderContextProvider value={{ settings: { fieldWrapper: FormField } }}>\\n <RenderNodeComponent node={rootNode} />\\n</RenderContextProvider>\\n```","examplesCount":1,"topics":["overview","form-wizard"],"sourcePath":"src/core/render-node.tsx","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderNodeControl","kind":"interface","signature":"export interface RenderNodeControl {\\n /** Принудительно скрыть/показать ноду, игнорируя условие hidden из схемы */\\n setHidden(value: boolean): this;\\n /** Убрать переопределение hidden — восстанавливает исходное условие из схемы */\\n resetHidden(): this;\\n /** Подмердить объект в componentProps ноды */\\n patchProps(partial: Record<string, unknown>): this;\\n /** Убрать переопределение пропсов — восстанавливает исходные componentProps из схемы */\\n resetProps(): this;\\n /**\\n * Получить React ref на компонент с данным selector.\\n * Ref создаётся один раз (idempotent) и передаётся в компонент через render-node.\\n * Компонент должен поддерживать ref (forwardRef или React 19 ref prop).\\n */\\n getRef<H>(): RefObject<H>;\\n /** @internal — selector этой ноды (используется standalone helpers hideWhen/renderEffect) */\\n __selector: string;\\n /** @internal — override maps схемы (используется standalone helpers) */\\n __overrideMaps: RenderSchemaOverrideMaps;\\n}","summary":"API для программного управления конкретной нодой схемы рендера.","description":"API для программного управления конкретной нодой схемы рендера.\\nПолучается через schema.node(selector).","params":[],"examplesCount":0,"topics":["render-behavior"],"sourcePath":"src/core/render-schema-proxy.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderSchemaFn","kind":"type","signature":"export type RenderSchemaFn<T> = () => RenderNode<T>;","summary":"Функция создания RenderSchema (M1).","description":"Функция создания RenderSchema (M1).\\n\\nВозвращает дерево узлов рендеринга. Привязка к данным — через сигналы модели в листьях\\n(`value: model.$.x`), поэтому аргумент-путь больше не нужен (legacy FieldPath удалён).","params":[],"example":"```typescript\\nconst renderSchema: RenderSchemaFn<MyForm> = () => ({\\n component: Box,\\n children: [\\n { value: model.$.email, component: InputField },\\n { value: model.$.password, component: InputPasswordField },\\n ],\\n});\\n```","examplesCount":1,"topics":["overview","render-schema","troubleshooting","cookbook"],"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"RenderSchemaProxy","kind":"type","signature":"export type RenderSchemaProxy<T> = RenderSchemaFn<T> & {\\n [PROXY_MARKER]: true;\\n /** Получить контроллер ноды по selector */\\n node(selector: string): RenderNodeControl;\\n /** @internal — карты переопределений для передачи через контекст */\\n __overrideMaps: RenderSchemaOverrideMaps;\\n};","summary":"RenderSchemaFn с дополнительным API программного управления.","description":"RenderSchemaFn с дополнительным API программного управления.\\nСоздаётся через createRenderSchema().","params":[],"examplesCount":0,"topics":["overview","render-schema","render-behavior","troubleshooting","cookbook"],"sourcePath":"src/core/render-schema-proxy.ts","entries":["."],"package":"@reformer/renderer-react","usage":4},{"name":"RenderTextPart","kind":"type","signature":"export type RenderTextPart = string | number | Signal<any>;","summary":"Часть текстового содержимого узла: литерал либо сигнал модели (`model.$.<path>`).","description":"Часть текстового содержимого узла: литерал либо сигнал модели (`model.$.<path>`).\\nСигнал подписывается точечно — при его изменении перерисовывается только текст,\\nа не поддерево узла.","params":[],"examplesCount":0,"sourcePath":"src/core/types.ts","entries":["."],"package":"@reformer/renderer-react"},{"name":"useReactForm","kind":"function","signature":"export function useFormBundle<B extends FormBundleLike>(factory: () => B): B","summary":"Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте (не при SSR — там эффекты не выполняются).","description":"Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте\\n(не при SSR — там эффекты не выполняются).","params":[["factory","- Фабрика бандла, обычно `() => createCoreForm({…})`."]],"returns":"Стабильный бандл.","example":"```tsx\\nconst credit = useFormBundle(() => createCoreForm<CreditForm>({ model: createCreditModel() }));\\n```","examplesCount":1,"topics":["overview","form-wizard"],"sourcePath":"../reformer/src/platforms/react/hooks/use-form-bundle.ts","entries":["."],"package":"@reformer/renderer-react","usage":6},{"name":"useRenderContext","kind":"function","signature":"export function useRenderContext<T = unknown>(): RenderContextValue<T>","summary":"Хук для получения контекста рендеринга.","description":"Хук для получения контекста рендеринга.\\n\\nИспользуется в пользовательских компонентах-контейнерах (например, wizard) для доступа\\nк `form` и `settings`. Бросает ошибку, если вызван вне {@link RenderContextProvider}\\n(его создаёт {@link FormRenderer}).","params":[],"returns":"","example":"Доступ к form/settings в self-managed компоненте\\n```tsx\\nfunction MyWizard({ children }) {\\nconst { form, settings } = useRenderContext();\\n\\nreturn (\\n<FormWizard form={form}>\\n{children.map((child) => (\\n<RenderNodeComponent node={child} form={form} />\\n))}\\n</FormWizard>\\n);\\n}\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/core/render-context.tsx","entries":["."],"package":"@reformer/renderer-react"},{"name":"VOID_HTML_TAGS","kind":"const","signature":"export const VOID_HTML_TAGS: ReadonlySet<string>","summary":"HTML void-элементы: не имеют содержимого.","description":"HTML void-элементы: не имеют содержимого. React бросает\\n«is a void element tag and must neither have children…», если такому тегу передать children,\\nпоэтому рендерер их содержимое не передаёт вовсе.","params":[],"examplesCount":0,"sourcePath":"src/core/utils.ts","entries":["."],"package":"@reformer/renderer-react"}]},"@reformer/renderer-json":{"schemaVersion":1,"package":"@reformer/renderer-json","version":"6.0.0","topics":[{"id":"overview","file":"01-overview.md","title":"Overview","purpose":"`@reformer/renderer-json` рендерит формы из декларативной **JSON-схемы** (M1, строковый операторный DSL). Схема — чистый JSON: привязки к модели и компонентам кодируются строками-операторами (`$model(...)`, `$component(...)`, `$dataSource(...)`), поэтому одну и ту же схему можно положить в `.json`, принять строкой с сервера/CMS и отрисовать в разных UI-китах через реестр.","keyConcepts":["**JSON-схема** — дерево `JsonNode` (см. [02-json-schema.md](02-json-schema.md)). Узлы: **field** (`value: \'$model(...)\'`), **array** (`array` + `item.$template`), **container** (`component` + `children`).","**Операторы** — строки `$model(path)` / `$component(Name)` / `$dataSource(NAME)`. Только они резолвятся; голые строки идут как есть.","**Модель (`model`)** — `FormModel`, источник данных. Передаётся пропом `model` в `JsonFormRenderer` (per-form состояние); листья биндятся к её сигналам.","**Реестр** — карта имени из `$component(...)`/`$dataSource(...)` на React-компонент или source-значение. Без регистрации схема не сконвертируется (ошибка `Component \\"X\\" not found in registry`).","**`FIELD_WRAPPER`** — зарезервированный ключ реестра (`\'$fieldWrapper\'`) для компонента-обёртки полей (label, error, hint). Обычно `FormField` из `@reformer/ui-kit`.","**Адаптеры контролов (`resolveFieldAdapter`)** — `JsonRendererSettings extends RendererSettings`, поэтому в `JsonRendererProvider` settings можно передать `resolveFieldAdapter(component) => FieldAdapter | undefined`. Value-based контролы (`Input` и пр.) регистрируются как есть; СЫРОЙ контрол чужого диалекта (Checkbox `checked` + `onChange(event)`, Select `onChange(value, option)`, Radio `onChange(event)`) регистрируется по имени в реестре, а адаптер переводит seam `value` + `onChange(value)` на его диалект — без обёртки на каждый контрол. Детали — [03-registry.md](03-registry.md).","**`createJsonForm` / `useJsonForm`** — сборка формы одним проходом: `createJsonForm({ schema, registry, initial | model, behavior?, validation?, renderBehavior?, seed?, setup? })` → `{ model, form, schema, registry, validation?, renderBehavior? }`; `useJsonForm(factory)` (тот же `useFormBundle` из core) держит бандл стабильным и армит живую валидацию. Отдаётся рендереру пропом `form`. См. [05-cookbook.md](05-cookbook.md).","**`defineJsonSchema<T>`** — идентити-хелпер, типизирующий литерал схемы по форме `T`: пути `$model(...)` сужаются до `Path<T>` (опечатка — ошибка компиляции), не нужен `as unknown as JsonFormSchema`. См. [02-json-schema.md](02-json-schema.md).","**`convertJsonToM1Tree`** — низкоуровневый конвертер JSON → RenderNode-дерево для `createForm({ model, schema })` (обычно скрыт за `createJsonForm`).","**`renderBehavior`** — TS-функция `RenderBehaviorFn<T>` (hideWhen/patchProps/onInit), применяется поверх готовой схемы; в JSON поведение не выражается. Задавай его полем конфига `createJsonForm` — фабрика `(form, model, validation?) => RenderBehaviorFn<T>` получает уже собранные сущности, а ссылка выходит стабильной по построению (иначе — dev-warn + пересборка дерева на каждый рендер)."],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[02-json-schema.md](02-json-schema.md) — формат `JsonFormSchema`/`JsonNode` и синтаксис операторов.","[03-registry.md](03-registry.md) — как наполнять реестр.","[04-troubleshooting.md](04-troubleshooting.md) — частые ошибки.","[05-cookbook.md](05-cookbook.md) — массивы, dataSource-функции, миграция из TS RenderSchema."],"sections":[{"heading":"Installation","slug":"installation"},{"heading":"Import Patterns","slug":"import-patterns"},{"heading":"Quick Start","slug":"quick-start"},{"heading":"Key Concepts","slug":"key-concepts"},{"heading":"Components and exports","slug":"components-and-exports"},{"heading":"See also","slug":"see-also"}],"terms":[["json",24],["model",24],["form",20],["schema",20],["registry",17],["component",13],["createjsonform",12],["renderbehavior",11],["reformer",10],["схема",9],["для",9],["usejsonform",9],["формы",7],["jsonformrenderer",7],["jsonrendererprovider",7],["сборка",7],["validation",7],["пропом",7],["value",7],["renderer",6],["схемы",6],["реестр",6],["definejsonschema",6],["jsonformschema",6],["datasource",5],["react",5],["field_wrapper",5],["одним",5],["myform",5],["email",5],["import",4],["defineregistry",4],["type",4],["box",4],["reg",4],["convertjsontom1tree",4],["бандл",4],["fieldwrapper",4],["либо",4],["validateschema",4],["как",4],["onchange",4],["cookbook",4],["можно",3],["строкой",3],["через",3],["kit",3],["from",3],["модель",3],["проходом",3],["formfield",3],["строки",3],["пути",3],["форме",3],["ошибка",3],["const",3],["input",3],["нужен",3],["initial",3],["форма",3],["per",3],["без",3],["обычно",3],["дерево",3],["jsonnode",3],["path",3],["реестра",3],["обёртки",3],["resolvefieldadapter",3],["операторов",3],["dsl",2],["модели",2],["поэтому",2],["схему",2],["сервера",2],["bash",2],["npm",2],["install",2],["core",2],["компонентов",2],["formmodel",2],["источник",2],["данных",2],["отдаётся",2],["рендереру",2],["inputfield",2],["операторы",2],["типизирует",2],["опечатка",2],["компиляции",2],["jsonschema",2],["children",2],["label",2],["field",2],["уже",2],["based",2],["адаптер",2],["ленивый",2],["usestate",2],["держит",2],["jsonform",2],["глобально",2],["провайдер",2],["settings",2],["рендер",2],["behavior",2],["seed",2],["setup",2],["сборку",2],["factory",2],["createrenderschemafromjsonm1",2],["форм",2],["onschemaready",2],["только",2],["поведение",2],["проп",2],["unknown",2],["рендерер",2],["array",2],["template",2],["name",2],["есть",2],["имени",2],["компонент",2],["ключ",2],["компонента",2],["полей",2],["контрол",2],["event",2],["его",2],["каждый",2],["литерал",2],["низкоуровневый",2],["rendernode",2],["createform",2],["renderbehaviorfn",2],["валидации",2],["настроек",2],["типы",2],["guards",2],["при",2],["ajv",2],["troubleshooting",2]]},{"id":"json-schema","file":"02-json-schema.md","title":"JSON Schema","purpose":"Схема — **чистый JSON** (M1, строковый операторный DSL): все привязки кодируются строками-операторами (`$model(...)`, `$component(...)`, `$dataSource(...)`, `$fn(...)`, `$locale(...)`), поэтому схему можно положить в `.json` или принять строкой с сервера/CMS. Голые строки (`label`, `placeholder`) резолвятся как есть.","keyConcepts":["**`JsonFormSchema`** — корневой документ: `version` (для миграций), опциональный `$schema` (путь к мета-схеме для IDE), единственный корневой узел `root`.","**`JsonNode`** — узел дерева. Дискриминированный union по строке-оператору, которую он несёт:","**field-node** (`JsonFieldNode`) — лист: `value: \'$model(path)\'` + опциональный `component: \'$component(Name)\'` (дефолт — Input). Не имеет `children`. Несёт **только layout** — валидаторов в JSON нет, оператора `$validator(...)` не существует. Валидация значений — отдельная TS-схема над моделью, см. [06-validation.md](06-validation.md).","**array-node** (`JsonArrayNode`) — массив: `array: \'$model(path)\'` + `item: { $template: <JsonNode> }` + `component: \'$component(FormArray)\'` (редактируемая секция) либо `\'$component(List)\'` (display-список без add/remove) + `initialValue` (литерал нового элемента для кнопки «Добавить»; нужен только редактируемой секции). Без `component` элементы отрисуются, но UI управления не будет — см. ниже.","**container-node** (`JsonContainerNode`) — контейнер (Box/Section/Wizard/Step): `component: \'$component(Name)\'` **или** нативный тег `\'$html(div)\'` + опциональные `children` (вложенные узлы и текстовые части вперемешку).","**Операторы** — единственный способ привязки (см. [`operators.ts`](../../src/operators.ts)):","`\'$model(path)\'` — путь к полю/массиву модели (лист → `model.signalAt(path)`, массив → value-прокси массива).","`\'$component(Name)\'` — имя компонента в реестре (`reg.component`).","`\'$html(tag)\'` — нативный HTML-тег для презентационной вёрстки без регистрации компонента. Тег проверяется по whitelist (`isAllowedHtmlTag`) и конвертером, и `validateFormSchema`.","`\'$dataSource(NAME)\'` — имя registry-source (`reg.dataSource`): options, itemLabel, константы, loading-компоненты.","`\'$fn(name)\'` — имя функции в реестре (`reg.fn`): форматтеры, компараторы, itemLabel, обработчики. Резолвится в саму функцию (передаётся в проп как есть). Отдельный от `$dataSource` вид — `validateSchema` ловит перепутанные `$fn`/`$dataSource` и `reg.fn` бросает на не-функцию.","`\'$locale(key)\'` — ключ строки для сервиса локализации (`reg.locale`). Резолвится в **строку на этапе конвертации** (`registry.getLocale().resolve(key)`); промах ключа / нет сервиса → сам ключ. Только `componentProps` (label/placeholder/title/aria-*), не структурные позиции. С параметрами — структурная форма `{ \\"$locale\\": \\"key\\", \\"params\\": { … } }` (объект, params — литералы). Реактивный/markdown-текст — компонент `$component(I18n)`, см. [08-i18n.md](08-i18n.md).","**`selector`** — plain-строка, id узла для render-behavior (`schema.node(\'…\')`, `hideWhen`, `patchProps`). **Не** путь модели.","**`componentProps`** — что прокидывается в React-компонент. Значения могут содержать строки-операторы (`\'$dataSource(NAME)\'`, `\'$model(...)\'`, `\'$component(...)\'`, `\'$fn(...)\'`, `\'$locale(...)\'`) или вложенные `JsonNode` — конвертер резолвит их рекурсивно. Обычные значения (числа, инлайн-массивы options, `label`) идут как есть."],"api":"","patterns":[],"antiPatterns":[{"note":"- **Голые строки вместо операторов** — `component: \'Input\'` или `value: \'email\'` не резолвятся. Нужны операторы: `component: \'$component(Input)\'`, `value: \'$model(email)\'`. Template-literal типы (`ModelOp`/`ComponentOp`) отловят это на этапе компиляции.\\n- **Использовать `selector` как путь к полю** — `selector` это id для behavior; путь задаётся только через `value`/`array` оператором `$model(...)`.\\n- **Забыть `item.$template` у массива** — array-node требует `array` **и** `item: { $template }`. Без `$template` `isArrayNode` вернёт false и узел не отрендерится как массив.\\n- **`initialValue` как FieldConfig** — это plain-литерал по форме элемента (`{ field: value }`), а не `{ value, component }`. Клонируется через `JSON.parse(JSON.stringify(...))`, поэтому только сериализуемые значения.\\n- **Ссылаться на `$dataSource(NAME)` без регистрации** — при `validateSchema` неизвестное имя даст ошибку; без валидации строка просто прокинется как есть (молчаливый баг).\\n- **Класть `validators` в field-node** — `JsonFieldNode` несёт только layout, поля `validators` в нём нет и оператора `$validator(...)` не существует. Валидация значений живёт в отдельной validation-схеме над моделью (`defineValidationSchema`, запуск `validateModel` из `@reformer/core/validation`), а не в JSON — см. [06-validation.md](06-validation.md).\\n- **Путать `$fn` и `$dataSource`** — функции регистрируй через `reg.fn` и ссылайся через `$fn(name)`, данные — через `reg.dataSource`/`$dataSource(NAME)`. Перекрёстное использование (`$fn(LOAN_TYPES)`, `$dataSource(comparator)`) `validateFormSchema` отклонит, а рантайм бросит. `reg.fn` дополнительно бросает при регистрации не-функции.\\n- **Аргументы у `$fn`** — оператор передаёт функцию **по ссылке**; биндинга аргументов (`$fn(goToStep, 2)`) нет. Нужен предзаданный аргумент — зарегистрируй уже связанную функцию через `reg.fn`.\\n- **`$locale` для reactive-переключения языка** — ключ резолвится в строку **на этапе конвертации** (иначе signal уронил бы строковые компоненты). Смена языка = новый сервис в `reg.locale` + пересборка дерева, а не «живое» обновление. Для live-переключения и markdown/rich — компонент `$component(I18n)` + `LocaleProvider`, см. [08-i18n.md](08-i18n.md).\\n- **Динамический/составной ключ `$locale`** — ключ это статичный литерал (`$locale(fields.email.label)`); вложить в него `$model(...)`/выражение нельзя. При наличии каталога опечатка ключа ловится на `validateSchema`; без каталога промах молча деградирует до самого ключа.\\n- **Регистрировать компонент ради статичного блока** — `reg.component(\'InfoBlock\', …)` для абзаца с текстом заменяется узлом `$html(div)`/`$html(p)` с текстом в `children`. Компонент нужен, когда есть своя логика или состояние.\\n- **`$component(div)` вместо `$html(div)`** — нативные теги живут в отдельном операторе и через реестр не резолвятся: `$component(div)` даст `unknown component \\"div\\"`.\\n- **Ждать от `$html` произвольной разметки** — оператор принимает ОДИН тег (`$html(div)`), а не HTML-фрагмент. Вложенность описывается `children`."}],"examples":[{"lang":"typescript","code":"import type { JsonFormSchema } from \'@reformer/renderer-json\';\\n\\nconst schema: JsonFormSchema = {\\n version: \'1.0\',\\n root: {\\n component: \'$component(Box)\',\\n children: [\\n {\\n selector: \'email\',\\n value: \'$model(email)\',\\n component: \'$component(Input)\',\\n componentProps: { label: \'Email\' },\\n },\\n ],\\n },\\n};"},{"lang":"typescript","code":"{\\n value: \'$model(personalData.firstName)\',\\n component: \'$component(Input)\',\\n}\\n\\n{\\n value: \'$model(loanType)\',\\n component: \'$component(Select)\',\\n componentProps: { label: \'Тип кредита\', options: \'$dataSource(LOAN_TYPES)\' },\\n}"},{"lang":"typescript","code":"{\\n value: \'$model(email)\',\\n component: \'$component(Input)\',\\n componentProps: {\\n label: \'$locale(fields.email.label)\', // → строка из сервиса локализации\\n placeholder: \'$locale(fields.email.placeholder)\',\\n // `$fn` подставляет функцию по ссылке — но только в проп, который у компонента есть.\\n // У `Input` пропа-форматтера нет: значение уйдёт в componentProps и будет проигнорировано.\\n // Пример настоящего функционального пропа — `itemLabel` у FormArray, см. ниже.\\n },\\n}"},{"lang":"typescript","code":"{\\n selector: \'properties-array\',\\n array: \'$model(properties)\',\\n initialValue: { type: \'apartment\', description: \'\', estimatedValue: 0, hasEncumbrance: false },\\n componentProps: {\\n title: \'$locale(properties.title)\',\\n addButtonLabel: \'$locale(properties.add)\',\\n itemLabel: \'$fn(propertyItemLabel)\',\\n },\\n item: {\\n $template: {\\n component: \'$component(Box)\',\\n componentProps: { className: \'space-y-3\' },\\n children: [\\n { value: \'$model(type)\', component: \'$component(Select)\',\\n componentProps: { label: \'Тип\', options: \'$dataSource(PROPERTY_TYPES)\' } },\\n { value: \'$model(estimatedValue)\', component: \'$component(Input)\',\\n componentProps: { label: \'Стоимость\', type: \'number\' } },\\n ],\\n },\\n },\\n}"}],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md) — как схема монтируется: реестр через `JsonRendererProvider`, модель — пропом `JsonFormRenderer`.","[03-registry.md](03-registry.md) — какие компоненты и source можно зарегистрировать.","[05-cookbook.md](05-cookbook.md) — `$template`, dataSource-функции, миграция из TS RenderSchema.","[06-validation.md](06-validation.md) — валидация значений (TS-схема над моделью + инъекция в wizard).","[Типы JsonFormSchema/JsonNode](../../src/types/json-schema.ts) и [операторы](../../src/operators.ts)."],"sections":[{"heading":"Key Concepts","slug":"key-concepts-2"},{"heading":"Type Guards","slug":"type-guards"},{"heading":"HTML-узлы (`$html`) и текст","slug":"html-uzly-html-i-tekst"},{"heading":"Examples","slug":"examples"},{"heading":"Anti-patterns","slug":"anti-patterns"},{"heading":"See also","slug":"see-also-2"}],"terms":[["component",62],["model",28],["html",21],["componentprops",18],["node",17],["datasource",16],["locale",16],["value",15],["children",15],["reg",13],["json",12],["для",12],["array",12],["template",12],["без",12],["label",10],["name",10],["через",10],["input",9],["email",9],["как",8],["jsonnode",8],["только",8],["validation",8],["list",8],["div",8],["текст",8],["компонент",8],["type",8],["схема",7],["или",7],["нет",7],["item",7],["initialvalue",7],["элемента",7],["это",7],["есть",6],["key",6],["путь",6],["массив",6],["нужен",6],["массива",6],["i18n",6],["selector",6],["typescript",6],["schema",5],["поэтому",5],["резолвятся",5],["path",5],["display",5],["список",5],["тег",5],["компонента",5],["itemlabel",5],["функцию",5],["ключ",5],["узла",5],["reformer",5],["строки",4],["placeholder",4],["jsonformschema",4],["несёт",4],["field",4],["add",4],["элементы",4],["box",4],["операторы",4],["src",4],["модели",4],["имя",4],["registry",4],["options",4],["функции",4],["строку",4],["title",4],["строка",4],["isarraynode",4],["classname",4],["значение",4],["properties",4],["можно",3],["узел",3],["лист",3],["валидация",3],["значений",3],["над",3],["моделью",3],["formarray",3],["редактируемая",3],["секция",3],["remove",3],["литерал",3],["будет",3],["узлы",3],["operators",3],["полю",3],["регистрации",3],["validateformschema",3],["компоненты",3],["резолвится",3],["validateschema",3],["сервиса",3],["этапе",3],["ключа",3],["behavior",3],["значения",3],["рендерер",3],["сигнал",3],["каталога",3],["поля",3],["select",3],["тип",3],["fields",3],["kit",3],["alerts",3],["alert",3],["реестр",3],["при",3],["привязки",2],["строкой",2],["сервера",2],["голые",2],["корневой",2],["version",2],["опциональный",2],["мета",2],["схеме",2],["единственный",2],["root",2],["дерева",2],["jsonfieldnode",2],["layout",2],["оператора",2],["validator",2],["существует",2],["добавить",2],["отрисуются",2],["управления",2],["ниже",2],["контейнер",2],["wizard",2],["нативный",2],["вложенные",2],["текстовые",2],["части",2],["реестре",2],["source",2],["обработчики",2],["проп",2],["отдельный",2],["бросает",2],["локализации",2],["конвертации",2],["промах",2],["aria",2],["params",2],["markdown",2],["plain",2],["идут",2],["import",2],["isfieldnode",2],["iscontainernode",2],["from",2],["renderer",2],["else",2],["описываются",2],["регистрировать",2],["ради",2],["число",2],["узлами",2],["реестра",2],["живёт",2],["разметка",2],["text",2],["теги",2],["data",2],["ошибка",2],["молчаливый",2],["нельзя",2],["всегда",2],["описывается",2],["loan_types",2],["функция",2],["ссылке",2],["пропа",2],["внутри",2],["пути",2],["относительно",2],["index",2],["estimatedvalue",2],["false",2],["space",2],["рендерится",2],["пропом",2],["message",2],["вместо",2],["типы",2],["даст",2],["validators",2],["оператор",2]]},{"id":"registry","file":"03-registry.md","title":"Component Registry","purpose":"Реестр — это карта от имени в операторе схемы (`$component(Name)` / `$dataSource(NAME)` / `$fn(name)`) на React-компонент, source-значение или функцию; плюс единственный сервис локализации для `$locale(key)`. Без регистрации компонент не отрендерится — будет ошибка вида _Component \\"X\\" not found in registry_.","keyConcepts":["**component** — любой React-компонент, зарегистрированный под именем и доступный в схеме как `component: \'$component(name)\'`. Один метод `reg.component(name, Component)` регистрирует и компоненты-листья (Input/Select — узел несёт `value: \'$model(path)\'`), и контейнеры-обёртки (Box/Section/FormField — узел несёт `children`). Роль узла (лист vs контейнер) определяется **структурой узла в схеме** (`value` vs `children`), а не тем, как компонент зарегистрирован. Лист получает value-based seam рендерера (`value` + `onChange(value)`). Сырой контрол UI-kit с другим диалектом (Checkbox — `checked` + `onChange(event)`, Select — `value` + `onChange(value, option)`, Radio — `value` + `onChange(event)`) регистрируется тем же `reg.component`, но требует `resolveFieldAdapter` в настройках `JsonRendererProvider` — рендерер сам переложит seam на диалект контрола (см. `FieldAdapter` / `RendererSettings.resolveFieldAdapter` в renderer-react). Обычным value-based контролам адаптер не нужен.","**`control` — только по запросу (§3.1, BREAKING)** — leaf-контрол по умолчанию больше **НЕ** получает проп `control` (ноду формы). Для двустороннего обмена значением ему хватает value-based seam (`value` + `onChange`); реактивные рантайм-пропы (догруженные `options`, `loading`, …) мёржит сам рендерер; label/error/touched обслуживает `FieldWrapper` (`FIELD_WRAPPER` / `FormField`) — а он `control` получает как раньше. Раньше `control` попадал в контрол по умолчанию, и адаптер нередко заводили лишь чтобы его вырезать (иначе нода текла бы в DOM) — теперь этого делать не нужно, `control` просто не передаётся. Если же контрол сам потребляет ноду (напр. вызывает `useFormControl(control)` ради её сигналов), включи передачу **явно**: статикой `Component.reformerNeedsControl = true` на самом компоненте либо `passControl: true` в его `FieldAdapter`. Оба флага независимы от seam-адаптации — контролу можно отдать `control`, не заводя адаптер, и наоборот (адаптер, переложивший диалект, `control` по-прежнему не передаёт, пока не выставлен `passControl`).","**dataSource value** — именованная константа, функция или React-компонент, на которые ссылаются строкой `\'$dataSource(NAME)\'` из `componentProps`. Регистрируется через `reg.dataSource(name, value)`.","**fn** — функция (форматтер/компаратор/itemLabel/обработчик), на которую ссылаются строкой `\'$fn(name)\'` из `componentProps`. Регистрируется через `reg.fn(name, fn)`. Отдельный от `dataSource` вид: `reg.fn` бросает при регистрации не-функции, а `validateFormSchema` ловит перепутанные `$fn`/`$dataSource`. Рантайм передаёт функцию в проп по ссылке (как `$dataSource`-функцию), новизна — в статической проверке.","**locale service** — сервис локализации для `$locale(key)` (строковый путь) и компонента `I18n` (реактивный путь). Регистрируется через `reg.locale(serviceOrResolver)` (ключ `LOCALE_SERVICE`) и/или подаётся в `LocaleProvider`. Интерфейс `LocaleService`: `resolve(key, params?) => string` (+ опциональный `render(key, params?) => ReactNode` для markdown/JSX, + `keys` для validate-проверки). Фабрики без зависимостей: `createLocaleResolver(catalog)` (плоский каталог), `createLocaleService(table)` (`ключ → (params) => строка` — параметры/склонение без ICU). ICU (`intl-messageformat`) и markdown подключает потребитель своей реализацией сервиса. Полный гид — [08-i18n.md](08-i18n.md).","**`FIELD_WRAPPER`** — зарезервированное имя (`\'$fieldWrapper\'`) для контейнера-обёртки полей (label, error, hint). Обычно регистрируется как `FormField` из `@reformer/ui-kit`."],"api":"","patterns":[],"antiPatterns":[{"note":"- **Забыть зарегистрировать `FIELD_WRAPPER`** — поля будут рендериться без обёртки (нет label/error). В большинстве случаев это ошибка.\\n- **Регистрировать React-element вместо компонента** — `reg.component(\'Input\', <Input />)` не сработает, нужно передавать сам тип компонента: `reg.component(\'Input\', Input)`.\\n- **Путать приоритет вложенных `JsonRendererProvider`** — реестры сливаются через `withParent`, и при дублях выигрывает **внутренний** (последний), как у `Object.assign`. Внешний провайдер задаёт базу, внутренний её перекрывает. Для программной композиции без React есть `composeRegistries(base, ...overrides)` с тем же правилом.\\n- **Использовать `$dataSource(NAME)` без регистрации** — без `validateSchema` строка просто прокинется в проп как есть (молчаливый баг); с `validateSchema` даст ошибку `unknown dataSource \\"NAME\\"`.\\n- **Ссылаться на dataSource как на компонент** — `component: \'$component(EMPTY_PLACEHOLDER)\'`, где `EMPTY_PLACEHOLDER` зарегистрирован через `reg.dataSource`, бросит `Entry \\"...\\" is a \'dataSource\' and cannot be used as $component(...)`. dataSource — только для значений в `componentProps`.\\n- **Регистрировать функцию как `dataSource` и ссылаться `$fn`** (или наоборот) — виды раздельны: `$fn(name)` резолвит только `reg.fn`-записи, `$dataSource(NAME)` — только `reg.dataSource`. Перекрёстная ссылка бросит `Entry \\"...\\" is a \'...\' and cannot be used as $fn(...)` и отклонится на `validateSchema`.\\n- **Регистрировать несколько сервисов локализации** — сервис один (кладётся под `LOCALE_SERVICE`); повторный `reg.locale(...)` перезапишет предыдущий. Разные языки — это разные каталоги, передаваемые в `reg.locale` по одному за раз.\\n- **Регистрировать сырой контрол без адаптера** — `reg.component(\'Checkbox\', RawCheckbox)`, где контрол читает значение из `checked` и эмитит DOM-событие (`onChange(event)`), при value-based seam запишет в модель сам объект события вместо булева. Такому контролу нужен `resolveFieldAdapter` в настройках `JsonRendererProvider` (`JsonRendererSettings` наследует `RendererSettings`, поэтому адаптер прокидывается тем же `settings`), который переложит seam на его диалект; текстовым и уже-value-based контролам адаптер не требуется.\\n- **Полагаться на проп `control` в leaf-контроле по умолчанию** (§3.1, BREAKING) — теперь он **НЕ** передаётся. Контрол, который вызывает `useFormControl(control)` (или иначе читает ноду), без opt-in получит `control === undefined` и упадёт/тихо не подпишется. Включи передачу явно: `Component.reformerNeedsControl = true` на компоненте либо `passControl: true` в его `FieldAdapter`. `FieldWrapper` (`FIELD_WRAPPER` / `FormField`) это не касается — обёртка `control` получает как прежде. И наоборот — **заводить адаптер лишь чтобы `strip`-нуть `control`** больше не нужно: по умолчанию его в пропах контрола нет."}],"examples":[{"lang":"typescript","code":"import { defineRegistry, FIELD_WRAPPER } from \'@reformer/renderer-json\';\\nimport { InputField, SelectField, Box, FormField } from \'@reformer/ui-kit\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.component(\'Input\', InputField);\\n reg.component(\'Select\', SelectField);\\n reg.component(\'Box\', Box);\\n reg.component(FIELD_WRAPPER, FormField);\\n});"},{"lang":"typescript","code":"const registry = defineRegistry((reg) => {\\n reg.component(\'Select\', SelectField);\\n reg.dataSource(\'LOAN_TYPES\', [\\n { value: \'consumer\', label: \'Потребительский\' },\\n { value: \'mortgage\', label: \'Ипотека\' },\\n ]);\\n});\\n\\n// В JSON-схеме (лист + операторы):\\n{\\n value: \'$model(loanType)\',\\n component: \'$component(Select)\',\\n componentProps: { options: \'$dataSource(LOAN_TYPES)\' },\\n}"},{"lang":"typescript","code":"import { defineRegistry, createLocaleResolver } from \'@reformer/renderer-json\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.component(\'Input\', InputField);\\n // функции — форматтеры, компараторы, itemLabel\\n reg.fn(\'propertyItemLabel\', (_control, index) => `Имущество #${index + 1}`);\\n reg.fn(\'formatCurrency\', (v: number) => `${v} ₽`);\\n // единственный сервис локализации; каталог включает validate-time проверку ключей\\n reg.locale(\\n createLocaleResolver({\\n \'fields.email.label\': \'Email\',\\n \'fields.email.placeholder\': \'you@example.com\',\\n })\\n );\\n});\\n\\n// В JSON-схеме:\\n{\\n value: \'$model(email)\',\\n component: \'$component(Input)\',\\n componentProps: {\\n label: \'$locale(fields.email.label)\', // → строка\\n },\\n}"},{"lang":"jsonc","code":"{\\n array: \'$model(properties)\',\\n component: \'$component(FormArray)\',\\n componentProps: {\\n itemLabel: \'$fn(propertyItemLabel)\', // → функция по ссылке\\n },\\n}"},{"lang":"typescript","code":"import { useFormControl } from \'@reformer/core\';\\n\\n// Контрол читает ноду напрямую (свои сигналы valid/errors/…):\\nfunction StepDots({ control }: { control: FieldNode<number> }) {\\n const { value, errors } = useFormControl(control);\\n // …\\n}\\nStepDots.reformerNeedsControl = true; // статика на компоненте — без адаптера\\n\\nconst registry = defineRegistry((reg) => {\\n reg.component(\'StepDots\', StepDots);\\n});\\n\\n// Альтернатива без статики — тем же адаптером (control + seam-диалект независимы):\\nconst settings: JsonRendererSettings = {\\n resolveFieldAdapter: (Component) =>\\n Component === StepDots ? { passControl: true } : undefined,\\n};"}],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md) — как реестр прокидывается через `JsonRendererProvider`.","[02-json-schema.md](02-json-schema.md) — где имена появляются в схеме (операторы `$component`/`$dataSource`/`$fn`/`$locale`)."],"sections":[{"heading":"Key Concepts","slug":"key-concepts-3"},{"heading":"Builder API","slug":"builder-api"},{"heading":"Examples","slug":"examples-2"},{"heading":"Anti-patterns","slug":"anti-patterns-2"},{"heading":"See also","slug":"see-also-3"}],"terms":[["component",35],["reg",34],["datasource",23],["value",22],["control",20],["name",18],["locale",14],["для",11],["без",11],["как",11],["input",9],["контрол",9],["компонент",8],["функцию",8],["label",8],["componentprops",8],["или",7],["сервис",7],["seam",7],["сам",7],["адаптер",7],["проп",7],["react",6],["локализации",6],["key",6],["схеме",6],["select",6],["formfield",6],["based",6],["onchange",6],["field_wrapper",6],["его",6],["true",6],["через",6],["defineregistry",6],["json",6],["const",6],["registry",5],["это",5],["регистрирует",5],["тем",5],["регистрируется",5],["только",5],["ноду",5],["компонента",5],["reformer",5],["email",5],["stepdots",5],["значение",4],["model",4],["box",4],["лист",4],["получает",4],["kit",4],["resolvefieldadapter",4],["jsonrendererprovider",4],["диалект",4],["умолчанию",4],["нужно",4],["useformcontrol",4],["passcontrol",4],["itemlabel",4],["при",4],["typescript",4],["import",4],["from",4],["fields",4],["который",4],["нет",4],["где",4],["читает",4],["регистрировать",4],["реестр",3],["единственный",3],["регистрации",3],["обёртки",3],["узла",3],["event",3],["контрола",3],["fieldadapter",3],["renderer",3],["контролам",3],["error",3],["fieldwrapper",3],["передаётся",3],["включи",3],["передачу",3],["явно",3],["reformerneedscontrol",3],["компоненте",3],["наоборот",3],["функция",3],["функции",3],["i18n",3],["params",3],["createlocaleresolver",3],["строка",3],["inputfield",3],["selectfield",3],["есть",3],["validateschema",3],["плюс",2],["ошибка",2],["под",2],["один",2],["узел",2],["несёт",2],["children",2],["роль",2],["контейнер",2],["зарегистрирован",2],["сырой",2],["checkbox",2],["checked",2],["настройках",2],["рендерер",2],["переложит",2],["renderersettings",2],["обычным",2],["нужен",2],["breaking",2],["leaf",2],["больше",2],["формы",2],["рантайм",2],["options",2],["раньше",2],["лишь",2],["чтобы",2],["иначе",2],["dom",2],["теперь",2],["этого",2],["просто",2],["потребляет",2],["вызывает",2],["либо",2],["независимы",2],["контролу",2],["передаёт",2],["ссылаются",2],["строкой",2],["бросает",2],["ссылке",2],["путь",2],["serviceorresolver",2],["ключ",2],["locale_service",2],["markdown",2],["validate",2],["каталог",2],["icu",2],["ссылка",2],["loan_types",2],["операторы",2],["propertyitemlabel",2],["index",2],["number",2],["действительно",2],["резолвится",2],["модель",2],["errors",2],["адаптера",2],["settings",2],["jsonrenderersettings",2],["undefined",2],["вместо",2],["внутренний",2],["ссылаться",2],["empty_placeholder",2],["бросит",2],["entry",2],["and",2],["cannot",2],["used",2],["разные",2],["прокидывается",2],["overview",2],["schema",2]]},{"id":"troubleshooting","file":"04-troubleshooting.md","title":"Troubleshooting / FAQ","purpose":"Имя из оператора `$component(X)` (или `$dataSource(X)`) не зарегистрировано в реестре. Проверь:","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md)","[02-json-schema.md](02-json-schema.md)","[03-registry.md](03-registry.md)","[05-cookbook.md](05-cookbook.md)"],"sections":[{"heading":"Component \\"X\\" not found in registry","slug":"component-x-not-found-in-registry"},{"heading":"Field renders without label/error","slug":"field-renders-without-label-error"},{"heading":"No model signal for \\"...\\" / `model` prop is required","slug":"no-model-signal-for-model-prop-is-required"},{"heading":"Сырой контрол UI-kit пишет в модель событие вместо значения","slug":"syroy-kontrol-ui-kit-pishet-v-model-sobytie-vmesto-znacheniya"},{"heading":"componentProps string passes through as plain string","slug":"componentprops-string-passes-through-as-plain-string"},{"heading":"useJsonRendererSettings throws outside provider","slug":"usejsonrenderersettings-throws-outside-provider"},{"heading":"\\"version\\" missing / invalid schema (при validate)","slug":"version-missing-invalid-schema-pri-validate"},{"heading":"Behavior selector matches nothing","slug":"behavior-selector-matches-nothing"},{"heading":"$template inside array doesn\'t render rows","slug":"template-inside-array-doesn-t-render-rows"},{"heading":"Массив рендерится без строк / пустой при добавлении","slug":"massiv-renderitsya-bez-strok-pustoy-pri-dobavlenii"},{"heading":"Toggle-видимость секции массива","slug":"toggle-vidimost-sektsii-massiva"},{"heading":"console.warn: `schema.node(...)` адресует неизвестный selector","slug":"console-warn-schema-node-adresuet-neizvestnyy-selector"},{"heading":"dev-warn: нестабильный `renderBehavior`","slug":"dev-warn-nestabilnyy-renderbehavior"},{"heading":"Битая схема при выключенном `validateSchema` → `SchemaErrorPanel`, а не белый экран","slug":"bitaya-shema-pri-vyklyuchennom-validateschema-schemaerrorpanel-a-ne-belyy-ekran"},{"heading":"See also","slug":"see-also-4"}],"terms":[["model",17],["schema",16],["component",12],["value",12],["selector",12],["renderbehavior",10],["как",8],["array",8],["если",7],["без",7],["node",7],["datasource",6],["jsonformrenderer",6],["через",6],["при",6],["json",6],["warn",6],["есть",6],["true",6],["behavior",6],["что",6],["registry",5],["jsonrendererprovider",5],["модель",5],["контрол",5],["вместо",5],["рендерер",5],["validateschema",5],["узел",5],["hidewhen",5],["properties",5],["имя",4],["или",4],["reg",4],["строка",4],["reformer",4],["renderer",4],["схемы",4],["seam",4],["каждый",4],["myform",4],["plain",4],["template",4],["элемента",4],["проверь",3],["зарегистрирован",3],["field_wrapper",3],["import",3],["from",3],["под",3],["path",3],["внутри",3],["событие",3],["значения",3],["onchange",3],["checked",3],["значение",3],["сам",3],["resolvefieldadapter",3],["return",3],["fromemit",3],["false",3],["cookbook",3],["это",3],["dev",3],["схему",3],["мета",3],["ошибки",3],["schemaerrorpanel",3],["схема",3],["только",3],["узла",3],["массив",3],["type",3],["initialvalue",3],["секции",3],["hasproperty",3],["const",3],["оператора",2],["схеме",2],["оператор",2],["голая",2],["реестром",2],["имени",2],["провайдер",2],["field",2],["label",2],["typescript",2],["formfield",2],["kit",2],["signal",2],["for",2],["prop",2],["required",2],["пропом",2],["структуре",2],["personaldata",2],["firstname",2],["поле",2],["реально",2],["сырой",2],["пишет",2],["рендерится",2],["checkbox",2],["dom",2],["radio",2],["строки",2],["причина",2],["based",2],["диалект",2],["option",2],["лишь",2],["fieldadapter",2],["tsx",2],["settings",2],["valueprop",2],["any",2],["target",2],["tovalue",2],["undefined",2],["react",2],["componentprops",2],["string",2],["name",2],["который",2],["либо",2],["usejsonrenderersettings",2],["режиме",2],["оберни",2],["version",2],["missing",2],["invalid",2],["ajv",2],["обход",2],["имён",2],["операторов",2],["container",2],["item",2],["пути",2],["они",2],["matches",2],["nothing",2],["patchprops",2],["убедись",2],["задан",2],["совпадает",2],["тем",2],["иначе",2],["форме",2],["пустой",2],["сигналов",2],["для",2],["полей",2],["все",2],["toggle",2],["видимость",2],["массива",2],["когда",2],["renderbehaviorfn",2],["signalat",2],["адресуется",2],["console",2],["промах",2],["узлу",2],["рендер",2],["usecallback",2],["белый",2],["экран",2],["раньше",2],["overview",2]]},{"id":"cookbook","file":"05-cookbook.md","title":"Cookbook","purpose":"Продвинутые рецепты для `@reformer/renderer-json` (M1, строковый операторный DSL). Всё сверено с рабочим кодом: конвертер — [json-to-render-schema.ts](../../src/converter/json-to-render-schema.ts), операторы — [operators.ts](../../src/operators.ts), реестр — [component-registry.ts](../../src/registry/component-registry.ts).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":["[01-overview.md](01-overview.md) — монтаж через `model` + `JsonRendererProvider`.","[02-json-schema.md](02-json-schema.md) — справочник по узлам `JsonNode` и операторам.","[03-registry.md](03-registry.md) — все методы `defineRegistry`.","[04-troubleshooting.md](04-troubleshooting.md) — типичные ошибки."],"sections":[{"heading":"Монтаж формы из JSON (M1) { #mounting }","slug":"montazh-formy-iz-json-m1-mounting"},{"heading":"Сборка формы одним проходом { #one-pass }","slug":"sborka-formy-odnim-prohodom-one-pass"},{"heading":"$template для массивов { #template-arrays }","slug":"template-dlya-massivov-template-arrays"},{"heading":"Display-список из массива модели { #display-list }","slug":"display-spisok-iz-massiva-modeli-display-list"},{"heading":"dataSource-значения и функции { #datasource }","slug":"datasource-znacheniya-i-funktsii-datasource"},{"heading":"Сырые контролы UI-kit без обёрток (FieldAdapter) { #field-adapter }","slug":"syrye-kontroly-ui-kit-bez-obertok-fieldadapter-field-adapter"},{"heading":"Инъекция runtime-сущностей в компонент (form, validation) { #inject-runtime }","slug":"inektsiya-runtime-suschnostey-v-komponent-form-validation-inject-runtime"},{"heading":"Вся форма read-only / view-mode { #readonly }","slug":"vsya-forma-read-only-view-mode-readonly"},{"heading":"Migration from TS RenderSchema { #migration }","slug":"migration-from-ts-renderschema-migration"},{"heading":"Презентационные блоки без регистрации компонентов { #html-nodes }","slug":"prezentatsionnye-bloki-bez-registratsii-komponentov-html-nodes"},{"heading":"See also","slug":"see-also-5"}],"terms":[["component",89],["model",72],["json",43],["schema",40],["componentprops",38],["form",34],["value",29],["registry",26],["reg",26],["datasource",24],["children",22],["для",19],["renderer",19],["react",19],["import",18],["const",18],["array",18],["reformer",17],["from",16],["type",15],["behavior",14],["html",14],["jsonformrenderer",13],["disable",13],["без",12],["myform",12],["item",12],["template",12],["disabled",12],["input",11],["node",11],["компонент",11],["classname",11],["problem",10],["solution",10],["через",10],["как",10],["jsonrendererprovider",10],["notes",10],["oninit",10],["label",10],["typescript",10],["схема",9],["один",9],["usememo",9],["значение",9],["initial",9],["creditform",9],["list",9],["checkbox",9],["формы",8],["convertjsontom1tree",8],["jsonform",8],["tsx",8],["settings",8],["createjsonform",8],["renderbehavior",8],["validation",8],["нужен",8],["box",8],["onchange",8],["initialvalue",8],["только",8],["src",7],["форма",7],["нужно",7],["модели",7],["пути",7],["проп",7],["personaldata",7],["path",7],["массив",7],["select",7],["options",7],["поля",7],["loan_types",7],["field",7],["mode",7],["section",7],["render",6],["реестр",6],["это",6],["раз",6],["либо",6],["createform",6],["createmodel",6],["jsonformschema",6],["unknown",6],["validateschema",6],["patchprops",6],["его",6],["usejsonform",6],["firstname",6],["нет",6],["renderbehaviorfn",6],["selector",6],["title",6],["kit",6],["узла",6],["defineregistry",6],["текст",6],["fieldadapter",6],["seam",6],["control",6],["wizard",6],["readonly",6],["email",6],["модель",5],["бандл",5],["сборка",5],["definejsonschema",5],["jsonschema",5],["return",5],["рендера",5],["нельзя",5],["внутри",5],["уже",5],["рендерера",5],["рендерер",5],["properties",5],["number",5],["name",5],["empty_placeholder",5],["antd",5],["checked",5],["radio",5],["resolvefieldadapter",5],["renderersettings",5],["formproxy",5],["всё",4],["схемы",4],["ровно",4],["одним",4],["проходом",4],["вариант",4],["createregistry",4],["function",4],["dev",4],["схеме",4],["если",4],["схему",4],["сборки",4],["factory",4],["formbehavior",4],["имя",4],["тот",4],["что",4],["элемента",4],["массива",4],["false",4],["имущество",4],["space",4],["строки",4],["alerts",4],["message",4],["amount",4],["сам",4],["emptyplaceholder",4],["контрол",4],["поэтому",4],["адаптер",4],["вся",4],["read",4],["only",4],["view",4],["после",4],["props",4],["inputfield",4],["grid",4],["text",4],["конвертер",3],["монтаж",3],["данные",3],["runtime",3],["данных",3],["получает",3],["ручной",3],["передаётся",3],["дважды",3],["рендереру",3],["собрать",3],["one",3],["pass",3],["meta",3],["env",3],["при",3],["вместо",3],["поведение",3],["compute",3],["полем",3],["hidewhen",3],["конфига",3],["loantype",3],["string",3],["ошибка",3],["остаётся",3],["вызывается",3],["тип",3],["itemlabel",3],["узел",3]]},{"id":"validation","file":"06-validation.md","title":"Validation","purpose":"Как валидировать **значения** формы, собранной из JSON-схемы (`@reformer/renderer-json`, M1). Всё сверено с рабочим кодом: типы узла — [json-schema.ts](../../src/types/json-schema.ts), структурная валидация — [validate.ts](../../src/validate.ts), исполнение над моделью — `validateModel` из `@reformer/core/validation` (рабочий пример — [registration-form-renderer-json/validation.ts](../../../../projects/react-playground/src/pages/demo/registration-form-renderer-json/validation.ts)).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Ждать, что `validateSchema={true}` (или `validateFormSchema`) валидирует значения** — этот проп проверяет только СТРУКТУРУ схемы через ajv (узлы + синтаксис операторов + имена компонентов). Введённые пользователем значения он не трогает. Валидацию значений исполняет раннер `validateModel` над моделью.\\n- **Пытаться добавить `validators` в JSON field-node** — `JsonFieldNode` несёт только layout (`value`/`component`/`componentProps`/`wrapper`). Поля `validators` в нём нет, оператора `$validator(...)` не существует. TypeScript отклонит лишнее поле; даже если протащить через `as`, конвертер его проигнорирует.\\n- **Инлайнить схему в `validateModel` или пересобирать её на каждый прогон** — схема это обычная функция над формой модели (`validate(model.$.path, [...])` адресует поле сигналом — стабильной ссылкой; значения читаются раннером в момент прогона). Держите схемы стабильными `const` через `defineValidationSchema`: `validateModel` отменяет устаревший прогон по идентичности схемы, а инлайн-стрелка (`validateModel(model, ({ model }) => …)`) каждый раз даёт новый прогон без дедупликации.\\n- **Забыть `selector: \'wizard\'` у wizard-ноды** — без `selector` узел не адресуется через `schema.node(\'wizard\')`, `onInit`/`patchProps` не найдут его и валидация не инъектируется (submit пройдёт без блокировки)."}],"examples":[],"troubleshooting":[],"seeAlso":["[07-form-wizard.md](07-form-wizard.md) — end-to-end wizard в JSON: submit (`onComponentEvent`), навигация (`renderEffect`), инъекция этой валидации, а также `defineSteps` из `@reformer/cdk` (сборка `validateStep`/`validateAll` по `selector`, `{ touch: true }` внутри).","[02-json-schema.md](02-json-schema.md) — справочник по узлам `JsonNode` (field-node несёт только layout).","[05-cookbook.md#inject-runtime](05-cookbook.md#inject-runtime) — общий приём инъекции runtime-сущностей через `onInit`/`patchProps`.","`@reformer/core` [13-multi-step.md](../../../reformer/docs/llms/13-multi-step.md) — операторы схемы валидации (`validate`/`validateAsync`/`validateWhen`/`cross`/`each`/`apply`), раннер `validateModel`, STEP_SCHEMAS.","[Типы JsonFormSchema/JsonNode](../../src/types/json-schema.ts) и [validate.ts](../../src/validate.ts) — структурная валидация схемы."],"sections":[{"heading":"Mental model — почему валидаторов нет в JSON { #mental-model }","slug":"mental-model-pochemu-validatorov-net-v-json-mental-model"},{"heading":"Шаг 1 — построить схему валидации над моделью { #build-schema }","slug":"shag-1-postroit-shemu-validatsii-nad-modelyu-build-schema"},{"heading":"Шаг 2 — исполнить: `{ validateStep, validateAll }` { #execute }","slug":"shag-2-ispolnit-validatestep-validateall-execute"},{"heading":"Показать ошибки провалидированных полей: `{ touch: true }` { #touch }","slug":"pokazat-oshibki-provalidirovannyh-poley-touch-true-touch"},{"heading":"Шаг 3 — инъекция в wizard через render-behavior { #inject }","slug":"shag-3-inektsiya-v-wizard-cherez-render-behavior-inject"},{"heading":"Полный рабочий пример { #full-example }","slug":"polnyy-rabochiy-primer-full-example"},{"heading":"Когда прогонять — декларативная стратегия { #strategy }","slug":"kogda-progonyat-deklarativnaya-strategiya-strategy"},{"heading":"Anti-patterns","slug":"anti-patterns-3"},{"heading":"See also","slug":"see-also-6"}],"terms":[["model",46],["reformer",38],["wizard",34],["json",32],["form",32],["schema",27],["core",23],["validate",21],["validatemodel",20],["creditform",20],["submit",19],["validation",17],["step",16],["через",15],["import",15],["from",15],["true",15],["touch",15],["поля",14],["схема",14],["const",14],["шага",13],["definevalidationschema",12],["behavior",12],["type",12],["схемы",11],["валидация",11],["только",11],["validateall",11],["renderer",10],["над",10],["для",10],["validatestep",10],["required",10],["src",9],["моделью",9],["валидации",9],["без",9],["formmodel",9],["ошибки",9],["node",9],["layout",8],["это",8],["step_schemas",8],["types",7],["нет",7],["selector",7],["валидацию",7],["render",7],["apply",7],["boolean",7],["cdk",7],["definesteps",7],["oninit",7],["значения",6],["правила",6],["validators",6],["validationschema",6],["контракт",6],["что",6],["шаг",6],["внутри",6],["поле",6],["typescript",6],["email",6],["step1",6],["step2",6],["promise",6],["multi",6],["прогон",6],["inject",6],["formproxy",6],["patchprops",6],["strategy",6],["формы",5],["всё",5],["операторы",5],["функция",5],["раннер",5],["схему",5],["sig",5],["правил",5],["если",5],["export",5],["makevalidationconfig",5],["далее",5],["runtime",5],["пример",4],["несёт",4],["component",4],["операторов",4],["тот",4],["при",4],["void",4],["рендера",4],["модели",4],["min",4],["minlength",4],["message",4],["раннера",4],["docs",4],["llms",4],["execute",4],["formwizardconfig",4],["fullschema",4],["emptyschema",4],["function",4],["return",4],["touched",4],["прогона",4],["инъекция",4],["cookbook",4],["renderbehaviorfn",4],["shared",4],["навигация",4],["рабочий",3],["react",3],["jsonfieldnode",3],["value",3],["componentprops",3],["html",3],["значений",3],["рантайм",3],["обычная",3],["инъектируется",3],["под",3],["композиция",3],["cross",3],["null",3],["field",3],["per",3],["схем",3],["ноды",3],["полная",3],["level",3],["момент",3],["конфиг",3],["steps",3],["loan",3],["applicant",3],["когда",3],["ноду",3],["общий",3],["createjsonrenderbehavior",3],["поведение",3],["visibility",3],["createsharedrenderbehavior",3],["его",3],["revalidatewhen",3],["стратегия",3],["или",3],["typed",3],["раскрывает",3],["debounce",3],["change",3],["каждый",3],["как",2],["типы",2],["структурная",2],["registration",2],["mental",2],["одна",2],["dsl",2],["wrapper",2],["ничего",2],["нём",2],["datasource",2],["operators",2],["оператора",2],["validator",2],["существует",2],["jsonformrenderer",2],["validateschema",2],["validateformschema",2],["структуру",2],["ajv",2],["синтаксис",2],["пользователем",2],["даже",2],["whitelist",2],["поэтому",2],["конвертер",2],["исполняет",2],["все",2],["можно",2],["дальше",2],["построить",2],["path",2],["max",2],["одного",2],["адресуются",2],["loantype",2],["выберите",2],["тип",2],["кредита",2],["loanamount",2],["минимум",2],["personaldata",2],["firstname",2],["шагов",2]]},{"id":"form-wizard","file":"07-form-wizard.md","title":"FormWizard","purpose":"End-to-end многошаговая форма (wizard) в `@reformer/renderer-json` (M1): **layout шагов** живёт в JSON-схеме, а **submit + навигация + условная видимость + инъекция валидации** — в `renderBehavior` (TS-функция `RenderBehaviorFn<T>`). JSON статичен и не выражает рантайм (`FormProxy`, колбэки, эффекты), поэтому wizard собирается из двух половин. Всё сверено с рабочим примером `complex-multy-step-form-renderer-json` и его shared-поведением из `complex-multy-step-form-renderer`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **Класть шаги в top-level `children` wizard-ноды** — шаги живут в `componentProps.steps`. Top-level `children` wizard-компонент не читает как шаги.\\n- **Ждать шаг как `{ number, title, icon, body }` в JSON** — это форма renderer-react. В JSON шаг — container-нода `$component(Step)` + `componentProps.title/icon` + `children`.\\n- **Считать `RendererFormWizard` библиотечным экспортом** — его нет в `@reformer/*`, это app-shim примера. Wizard-компонент подключается через реестр под любым именем; канон — ui-kit `FormWizard`, а сам шим кладётся в `renderer.wizard.tsx` или инлайном в `registry.ts`.\\n- **Называть файлы формы `json-schema.json` / `render-behavior.ts` / `schema.ts` / `behavior.ts`** — так называются исторические каталоги `complex-multy-step-form-*`, это НЕ канон и не «эталон нейминга». Канон для renderer-json: `index.tsx`, `types.ts`, `model.ts`, `renderer.schema.ts` (вариант — `.tsx` с JSX или `.json` как данные), `form.behavior.ts`, `renderer.behavior.ts`, `validation.ts`, `data-sources.ts`, `api.ts`, `registry.ts` (+ опциональный `renderer.wizard.tsx`). Полный набор — `@reformer/mcp` [06-form-directory-layout.md](../../../reformer-mcp/docs/llms/06-form-directory-layout.md) §1 либо `find_recipe directory-layout`.\\n- **Забыть `createWizardRenderBehavior` (только `onInit` с валидацией)** — форма будет валидировать, но `onSubmit`/навигация не подключатся: submit-less форма. Submit и навигация приходят из этого же behavior.\\n- **Ждать значения формы аргументом `onSubmit`** — `FormWizardProps.onSubmit` у ui-kit это `() => void | Promise<void>`, аргументов у него нет. Хендлер `onComponentEvent(wizard, \'onSubmit\', …)` тоже вызывается пустым; снимок берётся из модели (`model.get()`). Типизировать его как `(values: CreditForm) => …` — ошибка компиляции TS2322.\\n- **`renderEffect(node, ...)` вместо `renderEffect(schema, ...)`** — первый аргумент `renderEffect` это схема, а не узел (в отличие от `hideWhen`/`onComponentEvent`).\\n- **Забыть `selector: \'wizard\'`** — без селектора `schema.node(\'wizard\')` не адресует узел, инъекция/submit/навигация не навесятся.\\n- **Адресовать правила шагов массивом `STEP_SCHEMAS[step - 1]`** — привязка к позиции: вставка/перестановка шага молча разъезжается с индексами, а «забытый» шаг становится валидным по умолчанию. Собирай `FormWizardConfig` через `defineSteps` (адресация по `selector`, шаг без правил — явный `null`, `{ touch: true }` уже внутри) — см. [#define-steps](#define-steps)."}],"examples":[],"troubleshooting":[],"seeAlso":["[06-validation.md](06-validation.md) — `makeValidationConfig` (TS-схема над моделью), инъекция `validateStep`/`validateAll` в wizard.","[#define-steps](#define-steps) — `defineSteps` из `@reformer/cdk/form-wizard`: сборка `FormWizardConfig` из правил, адресованных по `selector` шага (рекомендуемая альтернатива массиву `STEP_SCHEMAS[step - 1]`).","[05-cookbook.md#inject-runtime](05-cookbook.md#inject-runtime) — общий приём инъекции runtime-сущностей (`form`) через `onInit`/`patchProps`.","renderer-react [03-render-behavior.md](../../../reformer-renderer-react/docs/llms/03-render-behavior.md) — семантика `hideWhen`/`renderEffect`/`onComponentEvent`/`onInit`.","renderer-react [01-overview.md](../../../reformer-renderer-react/docs/llms/01-overview.md#multi-step-forms) — канонический `FormWizard`, форма шага `{ number, title, icon, body }`."],"sections":[{"heading":"Половина 1 — layout шагов в JSON { #json-shape }","slug":"polovina-1-layout-shagov-v-json-json-shape"},{"heading":"Регистрируй свой wizard-компонент в реестре { #register }","slug":"registriruy-svoy-wizard-komponent-v-reestre-register"},{"heading":"Половина 2 — поведение в одном render-behavior { #render-behavior }","slug":"polovina-2-povedenie-v-odnom-render-behavior-render-behavior"},{"heading":"Конфиг валидации через `defineSteps` (адресация по selector) { #define-steps }","slug":"konfig-validatsii-cherez-definesteps-adresatsiya-po-selector-define-steps"},{"heading":"Anti-patterns","slug":"anti-patterns-4"},{"heading":"See also","slug":"see-also-7"}],"terms":[["wizard",49],["form",37],["renderer",33],["step",33],["reformer",28],["json",28],["component",22],["behavior",19],["schema",18],["шаг",18],["componentprops",15],["steps",15],["render",14],["selector",14],["import",14],["from",14],["через",13],["model",13],["react",13],["formwizard",11],["layout",11],["children",10],["title",10],["creditform",10],["validation",10],["submit",9],["docs",9],["icon",9],["validatestep",9],["tsx",8],["directory",8],["llms",8],["value",8],["компонент",8],["validateall",8],["cdk",8],["oncomponentevent",8],["rendereffect",8],["onsubmit",8],["без",8],["правила",8],["complex",7],["multy",7],["как",7],["mcp",7],["это",7],["шага",7],["type",7],["body",7],["oninit",7],["definesteps",7],["define",7],["шагов",6],["навигация",6],["инъекция",6],["его",6],["registry",6],["node",6],["overview",6],["под",6],["kit",6],["hidewhen",6],["правил",6],["форма",5],["схема",5],["container",5],["нода",5],["шаги",5],["канон",5],["formwizardconfig",5],["порядок",5],["wizardref",5],["makevalidationconfig",5],["формы",5],["для",5],["валидации",4],["renderbehaviorfn",4],["поведение",4],["там",4],["только",4],["mortgage",4],["section",4],["number",4],["имя",4],["внутри",4],["multi",4],["reg",4],["typescript",4],["ноду",4],["formmodel",4],["patchprops",4],["void",4],["step_schemas",4],["уже",4],["null",4],["touch",4],["true",4],["loan",4],["applicant",4],["confirm",4],["formproxy",3],["поэтому",3],["сверено",3],["опциональный",3],["шим",3],["массив",3],["top",3],["level",3],["input",3],["файл",3],["rendernode",3],["forms",3],["реестре",3],["mywizard",3],["над",3],["const",3],["shim",3],["rendererformwizard",3],["ноды",3],["сам",3],["узел",3],["именем",3],["types",3],["createwizardrenderbehavior",3],["config",3],["позиции",3],["или",3],["молча",3],["умолчанию",3],["валидным",3],["явно",3],["step1",3],["step2",3],["crossfieldrules",3],["makewizardconfig",3],["runtime",3],["end",2],["живёт",2],["renderbehavior",2],["рантайм",2],["всё",2],["имена",2],["есть",2],["jsx",2],["вариант",2],["данные",2],["полный",2],["набор",2],["find_recipe",2],["каталоги",2],["исторические",2],["файлы",2],["называются",2],["так",2],["половина",2],["каждый",2],["поддерево",2],["label",2],["схемы",2],["отличие",2],["регистрируй",2],["экспорт",2],["твой",2],["канонический",2],["принимает",2],["defineregistry",2],["app",2],["него",2],["либо",2],["инлайном",2],["один",2],["условные",2],["секции",2],["core",2],["formwizardhandle",2],["submitcreditapplication",2],["api",2],["export",2],["function",2],["return",2],["валидация",2],["моделью",2],["получает",2],["что",2],["аргументов",2],["promise",2],["значения",2],["модели",2],["аргументом",2],["валидировать",2],["get",2],["loantype",2],["current",2],["gotostep",2],["конфиг",2],["адресация",2],["execute",2],["массивом",2],["переставил",2],["валидирует",2]]},{"id":"i18n","file":"08-i18n.md","title":"i18n / Локализация","purpose":"`@reformer/renderer-json` **formatter-agnostic**: определяет только интерфейс `LocaleService` + фабрики-замыкания. ICU (`intl-messageformat`), i18next, markdown-рендерер подключает потребитель своей реализацией сервиса — у пакета нет i18n-зависимостей.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[{"note":"- **markdown/JSX в строковый проп** — `label: \\"$locale(...)\\"` с сервисом, возвращающим ReactNode, уронит компонент. Rich-контент только через `$component(I18n)` (или свой `$component(RichText)`).\\n- **реактивный параметр в строковом `$locale`** — `{ $locale, params: { count: \\"$model(...)\\" } }` берётся снимком и **не обновляется** (путь статичный); в dev печатается warning. Для реактивных model-параметров → `I18n` с `values`.\\n- **`I18n` без `LocaleProvider`** — без провайдера сервис по умолчанию отдаёт сам ключ (fallback-to-key). Оберни поддерево в `LocaleProvider`.\\n- **ждать live-переключения от `$locale`** — строковый путь статичен; смена языка для label/placeholder требует пересборки (новый сервис в `reg.locale` + пере-render). Live только у `I18n`.\\n- **тащить ICU/markdown в схему** — форматтер живёт в реализации `LocaleService` у потребителя, не в JSON."}],"examples":[],"troubleshooting":[],"seeAlso":["[02-json-schema.md](02-json-schema.md) — где `$locale`/`I18n` появляются в схеме.","[03-registry.md](03-registry.md) — `reg.locale`, `createLocaleService`, регистрация `I18n`.","[06-validation.md](06-validation.md) — валидация значений (отдельно от локализации)."],"sections":[{"heading":"Два пути (важно выбрать правильный)","slug":"dva-puti-vazhno-vybrat-pravilnyy"},{"heading":"Сервис локализации","slug":"servis-lokalizatsii"},{"heading":"Путь 1 — строковые пропы (статично)","slug":"put-1-strokovye-propy-statichno"},{"heading":"Путь 2 — реактивный компонент `I18n`","slug":"put-2-reaktivnyy-komponent-i18n"},{"heading":"Валидация","slug":"validatsiya"},{"heading":"Anti-patterns","slug":"anti-patterns-5"},{"heading":"See also","slug":"see-also-8"}],"terms":[["i18n",16],["locale",16],["count",13],["string",12],["путь",10],["component",10],["params",9],["markdown",8],["label",8],["key",8],["catalog",8],["model",8],["createlocaleservice",7],["localeprovider",7],["json",6],["сервис",6],["keys",6],["fields",6],["для",6],["service",6],["reg",6],["localeservice",5],["строковый",5],["rich",5],["компонент",5],["resolve",5],["строка",5],["render",5],["без",5],["const",5],["registry",5],["только",4],["icu",4],["messageformat",4],["или",4],["componentprops",4],["при",4],["языка",4],["live",4],["import",4],["from",4],["email",4],["min",4],["users",4],["schema",4],["values",4],["reformer",3],["renderer",3],["intl",3],["подключает",3],["потребитель",3],["jsx",3],["reactnode",3],["react",3],["реактивный",3],["record",3],["ключ",3],["минимум",3],["символов",3],["reactmarkdown",3],["параметров",3],["jsonc",3],["определяет",2],["фабрики",2],["сервиса",2],["нет",2],["один",2],["можно",2],["проп",2],["placeholder",2],["статично",2],["контент",2],["как",2],["уронит",2],["are",2],["конвертации",2],["смена",2],["рендера",2],["переключение",2],["локализации",2],["unknown",2],["проверка",2],["createlocaleresolver",2],["параметры",2],["plural",2],["сам",2],["intlmessageformat",2],["function",2],["return",2],["format",2],["object",2],["через",2],["оператор",2],["value",2],["input",2],["статичный",2],["берётся",2],["снимок",2],["значения",2],["печатается",2],["dev",2],["warning",2],["регистрация",2],["defineregistry",2],["реактивных",2],["переключения",2],["jsonformrenderer",2],["services",2],["lang",2],["jsonrendererprovider",2],["схеме",2],["обновляется",2],["смене",2],["валидация",2],["ключи",2],["validation",2]]},{"id":"review-checklist","file":"09-review-checklist.md","title":"Чек-лист ревью формы","purpose":"Короткий список для проверки формы на `@reformer` за пять минут. Собран по итогам реального переноса большой формы между UI-китами (см. рекомендации §10). Проверяет границы слоёв и типовые молчаливые поломки.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"Границы слоёв","slug":"granitsy-sloev"},{"heading":"Связи по строкам (ломаются молча)","slug":"svyazi-po-strokam-lomayutsya-molcha"},{"heading":"Валидация и видимость","slug":"validatsiya-i-vidimost"},{"heading":"Рендер и мост","slug":"render-i-most"},{"heading":"См. также","slug":"sm-takzhe"}],"terms":[["form",8],["иначе",6],["формы",5],["валидация",5],["только",4],["behavior",4],["validation",3],["над",3],["модели",3],["рендера",3],["поля",3],["validateschema",3],["dev",3],["рендер",3],["проверяет",2],["границы",2],["слоёв",2],["правила",2],["расчёты",2],["моста",2],["дерево",2],["видимость",2],["каждого",2],["который",2],["есть",2],["страницы",2],["опечатка",2],["model",2],["элемента",2],["это",2],["теперь",2],["пошаговая",2],["touch",2],["hidewhen",2],["value",2],["каждый",2],["createjsonform",2],["реестр",2],["overview",2],["wizard",2]]}],"symbols":[{"name":"ALLOWED_HTML_TAGS","kind":"const","signature":"export const ALLOWED_HTML_TAGS: ReadonlySet<string>","summary":"Разрешённые в `$html(...)` теги — presentational-разметка форм: блоки, типографика, списки, таблицы, медиа.","description":"Разрешённые в `$html(...)` теги — presentational-разметка форм: блоки, типографика, списки,\\nтаблицы, медиа. Намеренно НЕ входят: `script`/`style`/`link`/`meta`/`base` (исполнение и загрузка\\nресурсов), `iframe`/`object`/`embed` (встраивание чужого контекста), `form`/`button`/`input`/\\n`select`/`textarea` (управление формой — это поля схемы, а не вёрстка), `slot`/`template`.","params":[],"examplesCount":0,"sourcePath":"src/html/html-tags.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"allowOperatorStrings","kind":"function","signature":"export function allowOperatorStrings<T>(schema: T): T","summary":"Рекурсивно оборачивает КАЖДЫЙ проп схемы в `anyOf: [<честный тип>, operatorOp]`, чтобы автор схемы формы не дублировал escape-hatch руками: оператор-строка (`\\"$dataSource(LOAN_TYPES)\\"`, `\\"$fn(fmt)\\"`) допустима на месте любого значения componentProps.","description":"Рекурсивно оборачивает КАЖДЫЙ проп схемы в `anyOf: [<честный тип>, operatorOp]`, чтобы автор\\nсхемы формы не дублировал escape-hatch руками: оператор-строка (`\\"$dataSource(LOAN_TYPES)\\"`,\\n`\\"$fn(fmt)\\"`) допустима на месте любого значения componentProps. Спускается во вложенные\\n`properties` и `items`; сам объект в `anyOf` не оборачивается (componentProps — всегда объект).\\nСсылается на `#/definitions/operatorOp` — определение подставляет {@link toComponentPropsValidatorSchema}.","params":[["schema","- JSON Schema (обычно после {@link stripDocExtensions})."]],"returns":"Копия схемы с обёрнутыми пропами.","examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"buildFormSchemaMetaSchema","kind":"function","signature":"export function buildFormSchemaMetaSchema(\\n opts?: BuildFormSchemaMetaSchemaOptions\\n): Record<string, unknown>","summary":"Конкретная мета-схема: базовая + (если заданы `componentNames`) сужение `$component(...)` до enum допустимых значений (`[\\"$component(Input)\\", \\"$component(Select)\\", …]`).","description":"Конкретная мета-схема: базовая + (если заданы `componentNames`) сужение `$component(...)` до\\nenum допустимых значений (`[\\"$component(Input)\\", \\"$component(Select)\\", …]`). `$dataSource`-имена\\nJSON Schema\'й не покрыть (вложены в произвольный componentProps) — их проверяет рекурсивный обход\\nв `validateFormSchema`.\\n\\nenum, а не regex-`pattern`: ajv перечисляет допустимые имена в тексте ошибки, IDE даёт\\nавтодополнение по значениям, а имена не нужно экранировать под regex (напр. `$fieldWrapper`).\\n\\nЕсли задан `propSchemas`, в узлы, несущие `component`, добавляются `if/then`-ветки для IDE-подсветки\\ncomponentProps. В `if` обязателен `required: [\'component\']` — иначе нода без `component` (напр.\\narray-нода) вакуумно проходит `if` и получает чужой `then`.","params":[],"example":"```ts\\nconst schema = buildFormSchemaMetaSchema({ componentNames: getComponentNames(registry) });\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"BuildFormSchemaMetaSchemaOptions","kind":"interface","signature":"export interface BuildFormSchemaMetaSchemaOptions {\\n /** Имена компонентов реестра — сужают `$component(...)` до enum. */\\n componentNames?: string[];\\n /**\\n * Карта регистр-имя → схема componentProps. НОВОЕ необязательное поле: если задано, в `fieldNode`/\\n * `containerNode` добавляются `allOf`-ветки `if/then` (по одной на компонент) для IDE-подсветки\\n * componentProps через `$schema`. Реальную проверку делает рекурсивный обход в `validateFormSchema`\\n * (§ Props-компаньоны: `if/then` структурно недостижим для вложенных нод, годится только для IDE).\\n */\\n propSchemas?: Record<string, ComponentPropsSchema>;\\n}","summary":"Опции {@link buildFormSchemaMetaSchema}.","description":"Опции {@link buildFormSchemaMetaSchema}.","params":[],"examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"collectOperatorNames","kind":"function","signature":"export function collectOperatorNames(schema: JsonFormSchema): OperatorNames","summary":"Собирает имена операторов из схемы формы.","description":"Собирает имена операторов из схемы формы.","params":[["schema","- JSON-схема формы."]],"returns":"","example":"```typescript\\nconst used = collectOperatorNames(schema);\\nconst missing = used.components.filter((n) => !registry.has(n));\\nif (missing.length) throw new Error(`Не зарегистрированы: ${missing.join(\', \')}`);\\n```","examplesCount":1,"sourcePath":"src/collect-operator-names.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"collectSchemaSelectors","kind":"function","signature":"export function collectSchemaSelectors(schema: JsonFormSchema): Set<string>","summary":"Собирает множество всех `selector` из JSON-схемы (включая вложенные в `componentProps` ноды).","description":"Собирает множество всех `selector` из JSON-схемы (включая вложенные в `componentProps` ноды).","params":[["schema","- JSON-схема формы."]],"returns":"Множество известных селекторов.","examplesCount":0,"sourcePath":"src/collect-schema-selectors.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ComponentMetadata","kind":"interface","signature":"export interface ComponentMetadata<P = any> {\\n component: ComponentType<P> | unknown;\\n type: \'component\' | \'dataSource\' | \'fn\' | \'locale\';\\n description?: string;\\n}","summary":"Запись реестра.","description":"Запись реестра. Хранит значение (компонент / dataSource / функцию / сервис локализации) и его роль.","params":[],"example":"```typescript\\nconst meta: ComponentMetadata = registry.get(\'Input\')!;\\nmeta.type; // \'component\'\\n```","examplesCount":1,"sourcePath":"src/registry/types.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ComponentOp","kind":"type","signature":"export type ComponentOp = `$component(${string})`;","summary":"Строка-оператор ссылки на компонент реестра: `` `$component(${name})` ``.","description":"Строка-оператор ссылки на компонент реестра: `` `$component(${name})` ``.","params":[],"examplesCount":0,"topics":["overview","json-schema"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ComponentPropsSchema","kind":"type","signature":"export type ComponentPropsSchema = Record<string, unknown>;","summary":"Схема `componentProps` одного компонента (структурно = ui-kit `PropsSchema` после `mergeFieldPropsSchema`, но БЕЗ завязки на `@reformer/ui-kit`: renderer-json React-free и не зависит от ui-kit).","description":"Схема `componentProps` одного компонента (структурно = ui-kit `PropsSchema` после\\n`mergeFieldPropsSchema`, но БЕЗ завязки на `@reformer/ui-kit`: renderer-json React-free\\nи не зависит от ui-kit). Draft-07 JSON Schema плюс `x-*`-расширения (`x-doc`/`x-runtimeProps`/\\n`x-registryName`) — последние вырезаются перед компиляцией ajv ({@link stripDocExtensions}).","params":[],"examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ComponentRegistry","kind":"interface","signature":"export interface ComponentRegistry {\\n get(name: string): ComponentMetadata | undefined;\\n getDataSource<T = unknown>(name: string): T | undefined;\\n /**\\n * Единственный сервис локализации (для оператора `$locale(key)`), если зарегистрирован через\\n * `reg.locale(...)`. Опционален — сторонние реализации `ComponentRegistry` без него продолжают\\n * компилироваться; при его отсутствии `$locale` мягко деградирует до самого ключа.\\n */\\n getLocale?(): LocaleService | undefined;\\n has(name: string): boolean;\\n names(): string[];\\n}","summary":"Read-only API реестра, доступное в рантайме.","description":"Read-only API реестра, доступное в рантайме.\\n\\nСоздаётся через {@link defineRegistry}. Передаётся в `JsonRendererProvider`\\nчерез `settings.registry`.","params":[],"example":"```typescript\\nif (registry.has(\'Input\')) {\\n registry.get(\'Input\'); // ComponentMetadata\\n}\\nregistry.names(); // [\'Input\', \'Box\', \'LOAN_TYPES\', ...]\\n```","examplesCount":1,"sourcePath":"src/registry/types.ts","entries":["."],"package":"@reformer/renderer-json","usage":10},{"name":"composeRegistries","kind":"function","signature":"export function composeRegistries(...registries: readonly ComponentRegistry[]): ComponentRegistry","summary":"Композиция реестров слева направо: каждый следующий перекрывает предыдущие (last-wins, как `Object.assign`).","description":"Композиция реестров слева направо: каждый следующий перекрывает предыдущие\\n(last-wins, как `Object.assign`).\\n\\nПрограммная альтернатива вложенным {@link JsonRendererProvider}. Нужна там, где порядок\\nВЛАДЕНИЯ (форма → микрофронт → общее ядро) не совпадает с порядком React-дерева, а также\\nв не-React окружении и когда провайдер и рендерер оказываются в разных бандлах.","params":[["registries","- Реестры от наименее приоритетного к наиболее приоритетному."]],"returns":"Объединённый {@link ComponentRegistry}; пустой, если аргументов нет.","example":"Общее ядро + расширения микрофронта + специфика формы\\n```typescript\\nconst registry = composeRegistries(coreRegistry, mfeRegistry, formRegistry);\\n// formRegistry перекрывает mfeRegistry, тот — coreRegistry\\n```","examplesCount":1,"topics":["registry"],"sourcePath":"src/registry/component-registry.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"convertJsonToM1Tree","kind":"function","signature":"export function convertJsonToM1Tree<T>(\\n schema: JsonFormSchema,\\n registry: ComponentRegistry,\\n model: FormModel<T>\\n): RenderNode<T>","summary":"Сырое дерево RenderNode из JSON (M1) — для `createForm({ model, schema })`.","description":"Сырое дерево RenderNode из JSON (M1) — для `createForm({ model, schema })`. Листья привязываются\\nк сигналам модели (`\'$model(path)\'` → `model.signalAt`), компоненты/источники — из реестра.","params":[["schema","- JSON-схема формы ({@link JsonFormSchema})."],["registry","- Реестр компонентов/источников (см. {@link defineRegistry})."],["model","- Модель данных — источник значений (`FormModel`)."]],"returns":"Корневой {@link RenderNode} — кладётся в `createForm({ schema })`.","example":"Собрать форму из JSON-схемы (M1)\\n```ts\\nimport { createForm } from \'@reformer/core\';\\n\\nconst form = createForm<MyForm>({\\nmodel,\\nschema: convertJsonToM1Tree(jsonSchema, registry, model),\\nbehavior,\\n});\\n```","examplesCount":1,"topics":["overview","cookbook"],"sourcePath":"src/converter/json-to-render-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"createJsonForm","kind":"function","signature":"export function createJsonForm<T extends object>(config: CreateJsonFormConfig<T>): JsonForm<T>","summary":"Собирает форму из JSON-схемы за ОДИН проход: создаёт (или принимает) модель, конвертирует схему в дерево нод, строит форму, собирает валидацию и render-behavior.","description":"Собирает форму из JSON-схемы за ОДИН проход: создаёт (или принимает) модель, конвертирует схему в\\nдерево нод, строит форму, собирает валидацию и render-behavior. Схема передаётся один раз;\\nрезультат целиком отдаётся рендереру пропом `form`.","params":[["config","- {@link CreateJsonFormConfig}: `schema` + `registry` + (`initial` | `model`) + опц.\\n`behavior`, `validation`, `renderBehavior`, `seed`, `setup`."]],"returns":"","example":"```tsx\\nconst jsonForm = useJsonForm(() =>\\n createJsonForm<CreditForm>({\\n schema,\\n registry,\\n model: createCreditModel(),\\n behavior: formBehavior,\\n validation: { steps: { loan: loanRules }, extras: crossRules },\\n renderBehavior: makeCreditRenderBehavior,\\n })\\n);\\nreturn (\\n <JsonRendererProvider settings={{ registry: jsonForm.registry }}>\\n <JsonFormRenderer form={jsonForm} />\\n </JsonRendererProvider>\\n);\\n```","examplesCount":1,"topics":["overview","cookbook","review-checklist"],"sourcePath":"src/create-json-form.ts","entries":["."],"package":"@reformer/renderer-json","usage":20},{"name":"CreateJsonFormConfig","kind":"interface","signature":"export interface CreateJsonFormConfig<T> extends CreateFormConfigBase<T, JsonForm<T>> {\\n /** JSON-схема формы (типизируй по `T` через `defineJsonSchema<T>`). */\\n schema: JsonFormSchema<T>;\\n /** Реестр компонентов/source. */\\n registry: ComponentRegistry;\\n /** Фабрика render-behavior: получает уже собранные форму, модель и валидацию. */\\n renderBehavior?: (\\n form: FormProxy<T>,\\n model: FormModel<T>,\\n validation?: FormValidationBundle<T>\\n ) => RenderBehaviorFn<T>;\\n}","summary":"Конфиг {@link createJsonForm}.","description":"Конфиг {@link createJsonForm}. Модель — либо `initial` (создаётся внутри), либо готовая `model`.","params":[],"examplesCount":0,"sourcePath":"src/create-json-form.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"createLocaleResolver","kind":"function","signature":"export function createLocaleResolver(catalog: Record<string, string>): LocaleService","summary":"Строит {@link LocaleService} из каталога `ключ → строка`.","description":"Строит {@link LocaleService} из каталога `ключ → строка`. Промах ключа → сам ключ (fallback-to-key,\\nзеркало `createMessageResolver` из `@reformer/cdk`). `keys` каталога включает validate-time проверку\\nопечаток. Смена языка — пересобрать сервис на другом каталоге и передать новый ref в `reg.locale`.","params":[["catalog","- Таблица `ключ → локализованная строка`."]],"returns":"","example":"```ts\\nimport { defineRegistry } from \'@reformer/renderer-json\';\\nimport { createLocaleResolver } from \'@reformer/renderer-json\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.locale(createLocaleResolver({\\n \'fields.email.label\': \'Email\',\\n \'fields.email.placeholder\': \'you@example.com\',\\n }));\\n});\\n// В схеме: componentProps: { label: \'$locale(fields.email.label)\' }\\n// \'$locale(fields.unknown)\' при наличии каталога → ошибка на validateFormSchema.\\n```","examplesCount":1,"topics":["registry","cookbook","i18n"],"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json","usage":2},{"name":"createLocaleService","kind":"function","signature":"export function createLocaleService(\\n table: Record<string, (params?: LocaleParams) => string>\\n): LocaleService","summary":"Строит {@link LocaleService} из таблицы `ключ → (params) => строка` — 0-dependency вариант для параметров и склонения без ICU (стиль `createMessageResolver` из `@reformer/cdk`).","description":"Строит {@link LocaleService} из таблицы `ключ → (params) => строка` — 0-dependency вариант для\\nпараметров и склонения без ICU (стиль `createMessageResolver` из `@reformer/cdk`). Промах ключа →\\nсам ключ. `keys` таблицы включает validate-time проверку опечаток.\\n\\nДля ICU-склонения по CLDR-правилам подключи `intl-messageformat` в СВОЁМ сервисе:\\n`reg.locale({ resolve: (k, p) => new IntlMessageFormat(catalog[k], lng).format(p) as string, keys })`.\\nДля markdown добавь `render` (напр. через `react-markdown`).","params":[["table","- Таблица `ключ → (params) => локализованная строка`."]],"returns":"","example":"```ts\\nimport { createLocaleService } from \'@reformer/renderer-json\';\\n\\nconst ru = createLocaleService({\\n \'fields.min\': (p) => `Минимум ${p?.count} символов`,\\n \'users.count\': (p) => {\\n const n = Number(p?.count);\\n const forms = [\'пользователь\', \'пользователя\', \'пользователей\'];\\n const idx = n % 10 === 1 && n % 100 !== 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;\\n return `${n} ${forms[idx]}`;\\n },\\n});\\nru.resolve(\'fields.min\', { count: 3 }); // \'Минимум 3 символов\'\\n```","examplesCount":1,"topics":["registry","i18n"],"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"createRenderSchemaFromJsonM1","kind":"function","signature":"export function createRenderSchemaFromJsonM1<T>(\\n schema: JsonFormSchema,\\n registry: ComponentRegistry,\\n model: FormModel<T>\\n): RenderSchemaFn<T>","summary":"`RenderSchemaFn` из JSON (M1) — для `FormRenderer`/`JsonFormRenderer`.","description":"`RenderSchemaFn` из JSON (M1) — для `FormRenderer`/`JsonFormRenderer`. Листья привязываются к\\nсигналам модели (`\'$model(path)\'` → `model.signalAt`), компоненты/источники — из реестра.\\n\\nВ отличие от {@link convertJsonToM1Tree} (который возвращает готовое дерево), здесь результат —\\nленивая функция-фабрика дерева, как её ждёт `createRenderSchema`. Обычно вызывается внутри\\n{@link JsonFormRenderer}; напрямую нужен для интеграции с `FormRenderer` без JSON-обёртки.","params":[["schema","- JSON-схема формы ({@link JsonFormSchema})."],["registry","- Реестр компонентов/источников (см. {@link defineRegistry})."],["model","- Модель данных — источник значений (`FormModel`)."]],"returns":"`RenderSchemaFn<T>` — фабрика {@link RenderNode}-дерева для `createRenderSchema`.","example":"```ts\\nimport { createRenderSchema, FormRenderer } from \'@reformer/renderer-react\';\\n\\nconst fn = createRenderSchemaFromJsonM1<MyForm>(jsonSchema, registry, model);\\nconst proxy = createRenderSchema<MyForm>(fn);\\n<FormRenderer render={proxy} />;\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/converter/json-to-render-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"DataSourceOp","kind":"type","signature":"export type DataSourceOp = `$dataSource(${string})`;","summary":"Строка-оператор ссылки на registry-source: `` `$dataSource(${name})` ``.","description":"Строка-оператор ссылки на registry-source: `` `$dataSource(${name})` ``.","params":[],"examplesCount":0,"topics":["overview"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"defaultLocaleResolver","kind":"const","signature":"export const defaultLocaleResolver: LocaleResolver","summary":"Дефолтный резолвер: отдаёт сам ключ (fallback-to-key).","description":"Дефолтный резолвер: отдаёт сам ключ (fallback-to-key). Применяется, когда сервис не зарегистрирован.","params":[],"examplesCount":0,"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"defineJsonSchema","kind":"function","signature":"export function defineJsonSchema<T = unknown>(schema: JsonFormSchema<T>): JsonFormSchema<T>","summary":"Идентити-хелпер, ТИПИЗИРУЮЩИЙ литерал схемы по форме модели `T`: внутри `$model(...)` пути сужаются до {@link Path}<T> (опечатка ловится компилятором), и не нужен `as unknown as JsonFormSchema`.","description":"Идентити-хелпер, ТИПИЗИРУЮЩИЙ литерал схемы по форме модели `T`: внутри `$model(...)` пути\\nсужаются до {@link Path}<T> (опечатка ловится компилятором), и не нужен `as unknown as JsonFormSchema`.\\nДля схемы-строки-с-сервера (тип формы неизвестен) используйте `JsonFormSchema` без параметра.","params":[["schema","- Литерал схемы, типизируемый по `T`."]],"returns":"Та же схема с типом `JsonFormSchema<T>`.","example":"```ts\\ninterface CreditForm { loanType: string; personalData: { firstName: string } }\\nconst schema = defineJsonSchema<CreditForm>({\\n version: \'1.0\',\\n root: {\\n component: \'$component(Box)\',\\n children: [{ value: \'$model(personalData.firstName)\', component: \'$component(Input)\' }],\\n // { value: \'$model(loanTyp)\' } — ошибка компиляции: нет такого пути в CreditForm\\n },\\n});\\n```","examplesCount":1,"topics":["overview","cookbook","review-checklist"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"defineRegistry","kind":"function","signature":"export function defineRegistry(fn: (reg: RegistryBuilder) => void): ComponentRegistry","summary":"Создаёт реестр компонентов через builder-callback.","description":"Создаёт реестр компонентов через builder-callback.\\n\\nРеестр обязателен для работы {@link JsonFormRenderer} — иначе компоненты,\\nупомянутые в JSON-схеме, не отрезолвятся.","params":[["fn","- Builder-callback. Получает {@link RegistryBuilder} с методами `component`, `dataSource`."]],"returns":"Готовый {@link ComponentRegistry}, который кладётся в `JsonRendererProvider`.","example":"```typescript\\nimport { defineRegistry, FIELD_WRAPPER } from \'@reformer/renderer-json\';\\nimport { Input, Select, FormField } from \'@reformer/ui-kit\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.component(\'Input\', Input);\\n reg.component(\'Select\', Select);\\n reg.component(FIELD_WRAPPER, FormField);\\n reg.dataSource(\'LOAN_TYPES\', [\\n { value: \'consumer\', label: \'Потребительский\' },\\n { value: \'mortgage\', label: \'Ипотека\' },\\n ]);\\n});\\n```","examplesCount":1,"topics":["overview","registry","troubleshooting","cookbook","form-wizard","i18n"],"sourcePath":"src/registry/component-registry.ts","entries":["."],"package":"@reformer/renderer-json","usage":10},{"name":"FIELD_WRAPPER","kind":"const","signature":"export const FIELD_WRAPPER","summary":"Зарезервированный ключ реестра для контейнера-обёртки полей.","description":"Зарезервированный ключ реестра для контейнера-обёртки полей.\\n\\nЗарегистрируй компонент под этим именем (обычно `FormField` из `@reformer/ui-kit`),\\nчтобы каждое поле получало label, error и hint автоматически.","params":[],"example":"```typescript\\nimport { defineRegistry, FIELD_WRAPPER } from \'@reformer/renderer-json\';\\nimport { FormField } from \'@reformer/ui-kit\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.component(FIELD_WRAPPER, FormField);\\n});\\n```","examplesCount":1,"topics":["overview","registry","troubleshooting","cookbook"],"sourcePath":"src/registry/constants.ts","entries":["."],"package":"@reformer/renderer-json","usage":10},{"name":"FnOp","kind":"type","signature":"export type FnOp = `$fn(${string})`;","summary":"Строка-оператор ссылки на функцию реестра: `` `$fn(${name})` ``.","description":"Строка-оператор ссылки на функцию реестра: `` `$fn(${name})` ``.","params":[],"examplesCount":0,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"formSchemaMetaSchema","kind":"const","signature":"export const formSchemaMetaSchema","summary":"Базовая мета-схема form-DSL (draft-07): структура узлов + синтаксис операторов, имена компонентов НЕ ограничены (паттерн `$component(...)` открыт).","description":"Базовая мета-схема form-DSL (draft-07): структура узлов + синтаксис операторов, имена компонентов\\nНЕ ограничены (паттерн `$component(...)` открыт). Для сужения до конкретного реестра —\\n{@link buildFormSchemaMetaSchema}. Используется как `$schema` в IDE и как база валидатора.","params":[],"example":"Подключить как `$schema` в JSON-файле схемы\\n```ts\\n// record можно записать в файл и сослаться на него из \\"$schema\\" JSON-схемы.\\nformSchemaMetaSchema.$schema; // \'http://json-schema.org/draft-07/schema#\'\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"FormSchemaValidationResult","kind":"interface","signature":"export interface FormSchemaValidationResult {\\n valid: boolean;\\n /** Человекочитаемые ошибки (путь + сообщение). Пусто, если валидно. */\\n errors: string[];\\n}","summary":"Результат валидации схемы.","description":"Результат валидации схемы.","params":[],"examplesCount":0,"sourcePath":"src/validate.ts","entries":["./validate"],"package":"@reformer/renderer-json"},{"name":"getComponentNames","kind":"function","signature":"export function getComponentNames(registry: ComponentRegistry): string[]","summary":"Имена компонентов реестра (тип `component`) — то, что валидно в `$component(...)`.","description":"Имена компонентов реестра (тип `component`) — то, что валидно в `$component(...)`.","params":[["registry","- Реестр (см. {@link defineRegistry})."]],"returns":"Массив имён компонентов.","example":"Сузить мета-схему до компонентов реестра\\n```ts\\nconst names = getComponentNames(registry); // [\'Input\', \'Select\', \'Box\', ...]\\nconst schema = buildFormSchemaMetaSchema({ componentNames: names });\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"getDataSourceNames","kind":"function","signature":"export function getDataSourceNames(registry: ComponentRegistry): string[]","summary":"Имена registry-dataSource (`reg.dataSource`) — то, что валидно в `$dataSource(...)`: options/itemLabel/константы/loading-компоненты.","description":"Имена registry-dataSource (`reg.dataSource`) — то, что валидно в `$dataSource(...)`:\\noptions/itemLabel/константы/loading-компоненты.","params":[["registry","- Реестр (см. {@link defineRegistry})."]],"returns":"Массив имён источников.","example":"```ts\\ngetDataSourceNames(registry); // [\'LOAN_TYPES\', \'GENDERS\', \'CURRENT_YEAR\', ...]\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"getFnNames","kind":"function","signature":"export function getFnNames(registry: ComponentRegistry): string[]","summary":"Имена функций реестра (`reg.fn`) — то, что валидно в `$fn(...)`: форматтеры/компараторы/itemLabel/ обработчики.","description":"Имена функций реестра (`reg.fn`) — то, что валидно в `$fn(...)`: форматтеры/компараторы/itemLabel/\\nобработчики. Отдельно от {@link getDataSourceNames}, поэтому `validateFormSchema` ловит перепутанные\\n`$fn`/`$dataSource`.","params":[["registry","- Реестр (см. {@link defineRegistry})."]],"returns":"Массив имён функций.","examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"getLocaleKeys","kind":"function","signature":"export function getLocaleKeys(registry: ComponentRegistry): readonly string[] | undefined","summary":"Известные ключи локализации сервиса реестра (`reg.locale` с каталогом) — то, что валидно в `$locale(...)`.","description":"Известные ключи локализации сервиса реестра (`reg.locale` с каталогом) — то, что валидно в\\n`$locale(...)`. `undefined`, если сервис не зарегистрирован или задан голым резолвером без `keys`\\n(тогда `validateFormSchema` мягко пропускает проверку ключей, как для `$model`-путей).","params":[["registry","- Реестр (см. {@link defineRegistry})."]],"returns":"Массив ключей либо `undefined`.","examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"HtmlOp","kind":"type","signature":"export type HtmlOp = `$html(${string})`;","summary":"Строка-оператор нативного HTML-тега: `` `$html(${tag})` ``.","description":"Строка-оператор нативного HTML-тега: `` `$html(${tag})` ``. Позволяет верстать презентационные\\nблоки (заголовки, абзацы, разделители) прямо в схеме, не регистрируя ради них компонент.\\nТег проверяется по whitelist (`isAllowedHtmlTag`) и конвертером, и `validateFormSchema`.","params":[],"examplesCount":0,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"I18n","kind":"function","signature":"export function I18n({ id, values }: I18nProps): ReactNode","summary":"Реактивный локализованный текст.","description":"Реактивный локализованный текст. Читает {@link LocaleService} из {@link LocaleProvider} (live-смена\\nязыка) и разворачивает `values`-сигналы (live-обновление параметров). Если сервис умеет `render` —\\nрендерит rich-контент (markdown/JSX), иначе строку через `resolve`.","params":[["props","- {@link I18nProps} (`id` + опциональные `values`)."]],"returns":"Локализованный `ReactNode`.","examplesCount":0,"topics":["json-schema","registry","i18n"],"sourcePath":"src/locale/i18n.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"I18nProps","kind":"interface","signature":"export interface I18nProps {\\n /** Ключ сообщения в сервисе локализации. */\\n id: string;\\n /**\\n * Параметры интерполяции/склонения. Значения могут быть сигналами (`$model(...)`) — тогда текст\\n * обновляется при их изменении — или литералами.\\n */\\n values?: LocaleParams;\\n}","summary":"Props {@link I18n}.","description":"Props {@link I18n}.","params":[],"examplesCount":0,"sourcePath":"src/locale/i18n.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"isAllowedHtmlTag","kind":"function","signature":"export function isAllowedHtmlTag(tag: string): boolean","summary":"Тег разрешён в `$html(...)`?","description":"Тег разрешён в `$html(...)`?","params":[["tag","- Имя тега из оператора (регистр приводится к нижнему)."]],"returns":"`true`, если тег входит в {@link ALLOWED_HTML_TAGS}.","example":"```ts\\nisAllowedHtmlTag(\'p\'); // true\\nisAllowedHtmlTag(\'script\'); // false\\n```","examplesCount":1,"topics":["json-schema"],"sourcePath":"src/html/html-tags.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isArrayNode","kind":"function","signature":"export function isArrayNode(node: JsonNode): node is JsonArrayNode","summary":"Type-guard: узел — массив (`array: \'$model(...)\'` + `item.$template`).","description":"Type-guard: узел — массив (`array: \'$model(...)\'` + `item.$template`). Проверять ПЕРВЫМ\\n(лист/контейнер отсеиваются после, т.к. массив тоже несёт `$model`).","params":[["node","- Узел JSON-схемы."]],"returns":"`true`, если узел — {@link JsonArrayNode}.","example":"Сузить тип узла перед доступом к `item.$template`\\n```ts\\nif (isArrayNode(node)) {\\nnode.array; // ModelOp\\nnode.item.$template; // JsonNode\\n}\\n```","examplesCount":1,"topics":["overview","json-schema","troubleshooting","cookbook"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isComponentOp","kind":"const","signature":"export const isComponentOp","summary":"Type-guard: строка — оператор `\\"$component(...)\\"` (ссылка на компонент реестра).","description":"Type-guard: строка — оператор `\\"$component(...)\\"` (ссылка на компонент реестра).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link ComponentOp}.","example":"```ts\\nif (isComponentOp(node.component)) {\\n const name = parseOperator(node.component)!.arg; // \'Select\'\\n}\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isContainerNode","kind":"function","signature":"export function isContainerNode(node: JsonNode): node is JsonContainerNode","summary":"Type-guard: узел — контейнер (`component: \'$component(...)\'` или `\'$html(...)\'`, без `value`/`array`).","description":"Type-guard: узел — контейнер (`component: \'$component(...)\'` или `\'$html(...)\'`,\\nбез `value`/`array`).","params":[["node","- Узел JSON-схемы."]],"returns":"`true`, если узел — {@link JsonContainerNode}.","example":"Сузить тип узла перед обходом `children`\\n```ts\\nif (isContainerNode(node)) {\\nnode.component; // ComponentOp | HtmlOp\\nnode.children?.forEach(walk);\\n}\\n```","examplesCount":1,"topics":["overview","json-schema"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isDataSourceOp","kind":"const","signature":"export const isDataSourceOp","summary":"Type-guard: строка — оператор `\\"$dataSource(...)\\"` (ссылка на registry-source).","description":"Type-guard: строка — оператор `\\"$dataSource(...)\\"` (ссылка на registry-source).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link DataSourceOp}.","example":"```ts\\nif (isDataSourceOp(props.options)) {\\n const name = parseOperator(props.options)!.arg; // \'LOAN_TYPES\'\\n}\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isFieldNode","kind":"function","signature":"export function isFieldNode(node: JsonNode): node is JsonFieldNode","summary":"Type-guard: узел — лист (`value: \'$model(...)\'`).","description":"Type-guard: узел — лист (`value: \'$model(...)\'`).","params":[["node","- Узел JSON-схемы."]],"returns":"`true`, если узел — {@link JsonFieldNode}.","example":"Сузить тип узла перед доступом к `value`/`component`\\n```ts\\nif (isFieldNode(node)) {\\nnode.value; // ModelOp\\nnode.component; // ComponentOp | undefined\\n}\\n```","examplesCount":1,"topics":["overview","json-schema"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isFnOp","kind":"const","signature":"export const isFnOp","summary":"Type-guard: строка — оператор `\\"$fn(...)\\"` (ссылка на функцию реестра).","description":"Type-guard: строка — оператор `\\"$fn(...)\\"` (ссылка на функцию реестра).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link FnOp}.","example":"```ts\\nif (isFnOp(props.itemLabel)) {\\n const name = parseOperator(props.itemLabel)!.arg; // \'propertyItemLabel\'\\n}\\n```","examplesCount":1,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isHtmlOp","kind":"const","signature":"export const isHtmlOp","summary":"Type-guard: строка — оператор `\\"$html(...)\\"` (нативный HTML-тег).","description":"Type-guard: строка — оператор `\\"$html(...)\\"` (нативный HTML-тег).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link HtmlOp}.","example":"```ts\\nif (isHtmlOp(node.component)) {\\n const tag = parseOperator(node.component)!.arg; // \'p\'\\n}\\n```","examplesCount":1,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isLocaleOp","kind":"const","signature":"export const isLocaleOp","summary":"Type-guard: строка — оператор `\\"$locale(...)\\"` (ключ строки для сервиса локализации).","description":"Type-guard: строка — оператор `\\"$locale(...)\\"` (ключ строки для сервиса локализации).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link LocaleOp}.","example":"```ts\\nif (isLocaleOp(props.label)) {\\n const key = parseOperator(props.label)!.arg; // \'fields.email.label\'\\n}\\n```","examplesCount":1,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"isModelOp","kind":"const","signature":"export const isModelOp","summary":"Type-guard: строка — оператор `\\"$model(...)\\"` (привязка к полю/массиву модели).","description":"Type-guard: строка — оператор `\\"$model(...)\\"` (привязка к полю/массиву модели).","params":[["v","- Проверяемое значение."]],"returns":"`true`, если `v` — {@link ModelOp}.","example":"Сузить тип значения prop до ModelOp\\n```ts\\nif (isModelOp(value)) {\\nconst path = parseOperator(value)!.arg; // \'loanType\'\\n}\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonArrayNode","kind":"interface","signature":"export interface JsonArrayNode<T = unknown> {\\n /** Id для render-behavior. */\\n /**\\n * Стабильный идентификатор узла, 8 символов base36. Выдаётся инструментом (билдером),\\n * а не автором: `selector` человек пишет руками и адресует им поведение рендера,\\n * `$nodeId` машина выдаёт при разборе и в поведении не адресуется.\\n *\\n * Конвертером **игнорируется** — до render-узла и до DOM не доходит.\\n */\\n $nodeId?: string;\\n selector?: string;\\n /** Привязка к массиву модели: `\'$model(coBorrowers)\'`. С типом `T` путь сужается до {@link Path}<T>. */\\n array: ModelOp<T>;\\n /**\\n * Шаблон под-схемы элемента (внутри `$model(...)` относителен к ЭЛЕМЕНТУ, не к корню `T`),\\n * поэтому его пути остаются нетипизированными (`JsonNode` без параметра).\\n */\\n item: { $template: JsonNode };\\n /**\\n * Компонент-рендерер массива (`\'$component(List)\'`). Опционален: без него — встроенная\\n * редактируемая секция. С ним рендер идёт этим компонентом (он получает контрол массива,\\n * `item`-фабрику и готовые элементы children).\\n */\\n component?: ComponentOp;\\n /**\\n * «Пустой» элемент для кнопки «Добавить» (литерал-объект по форме элемента).\\n * Нужен, т.к. листья шаблона несут `value: \'$model(...)\'`, а не литерал-дефолт. Только для\\n * редактируемого (встроенного) пути.\\n */\\n initialValue?: Record<string, unknown>;\\n /** Оформление секции массива / пропсы компонента-рендерера. */\\n componentProps?: Record<string, unknown>;\\n}","summary":"Итерация массива модели (`$model`) + шаблон элемента (`$template`).","description":"Итерация массива модели (`$model`) + шаблон элемента (`$template`).\\n\\nПо умолчанию рендерится встроенной редактируемой секцией (add/remove/reorder). Опциональный\\n`component` уводит рендер на зарегистрированный компонент — например `\'$component(List)\'` для\\nchrome-less display-списка (алерты) или своя секция с кастомным хромом. Дисплей-vs-редактирование —\\nэто выбор компонента, а не отдельный тип узла. `initialValue` нужен только редактируемому пути\\n(кнопка «Добавить»); при `component` display-компоненты его игнорируют.","params":[],"examplesCount":0,"topics":["overview","json-schema"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonChild","kind":"type","signature":"export type JsonChild<T = unknown> = JsonNode<T> | JsonTextChild;","summary":"Элемент `children`: вложенный узел либо текстовая часть ({@link JsonTextChild}).","description":"Элемент `children`: вложенный узел либо текстовая часть ({@link JsonTextChild}).","params":[],"examplesCount":0,"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonContainerNode","kind":"interface","signature":"export interface JsonContainerNode<T = unknown> {\\n /** Id для render-behavior. */\\n /**\\n * Стабильный идентификатор узла, 8 символов base36. Выдаётся инструментом (билдером),\\n * а не автором: `selector` человек пишет руками и адресует им поведение рендера,\\n * `$nodeId` машина выдаёт при разборе и в поведении не адресуется.\\n *\\n * Конвертером **игнорируется** — до render-узла и до DOM не доходит.\\n */\\n $nodeId?: string;\\n selector?: string;\\n /**\\n * Компонент-контейнер из реестра (`\'$component(Section)\'`) либо нативный HTML-тег\\n * (`\'$html(div)\'`). Для тега `componentProps` — DOM-атрибуты, и они проходят чистку\\n * (`sanitizeHtmlProps`): обработчики `on*`, `dangerouslySetInnerHTML` и `javascript:`-URL\\n * отбрасываются.\\n */\\n component: ComponentOp | HtmlOp;\\n /** Props компонента; значения могут содержать строки-операторы или вложенные узлы. */\\n componentProps?: Record<string, unknown>;\\n /**\\n * Содержимое узла: вложенные узлы и текстовые части ({@link JsonTextChild}) в любом порядке —\\n * текст можно ставить и после узла (`[{ \\"component\\": \\"$html(b)\\", … }, \\" и далее текст\\"]`).\\n */\\n children?: JsonChild<T>[];\\n}","summary":"Контейнер (Box/Section/Wizard/Step/…) с дочерними узлами — либо блок нативной вёрстки (`\'$html(div)\'`), для которого не нужен зарегистрированный компонент.","description":"Контейнер (Box/Section/Wizard/Step/…) с дочерними узлами — либо блок нативной вёрстки\\n(`\'$html(div)\'`), для которого не нужен зарегистрированный компонент.","params":[],"examplesCount":0,"topics":["overview","json-schema"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonFieldNode","kind":"interface","signature":"export interface JsonFieldNode<T = unknown> {\\n /** Id для render-behavior (hideWhen/patchProps). Опционален. */\\n /**\\n * Стабильный идентификатор узла, 8 символов base36. Выдаётся инструментом (билдером),\\n * а не автором: `selector` человек пишет руками и адресует им поведение рендера,\\n * `$nodeId` машина выдаёт при разборе и в поведении не адресуется.\\n *\\n * Конвертером **игнорируется** — до render-узла и до DOM не доходит.\\n */\\n $nodeId?: string;\\n selector?: string;\\n /** Привязка к сигналу модели: `\'$model(personalData.lastName)\'`. С типом `T` путь сужается до {@link Path}<T>. */\\n value: ModelOp<T>;\\n /** Компонент поля из реестра: `\'$component(Select)\'`. Опционален. */\\n component?: ComponentOp;\\n /** Props компонента; значения могут содержать строки-операторы (`\'$dataSource(NAME)\'`) или вложенные узлы. */\\n componentProps?: Record<string, unknown>;\\n /** Обёртка поля (например, FormField). */\\n wrapper?: JsonNode<T>;\\n}","summary":"Лист формы: значение из модели (`$model`) + опциональный компонент (`$component`, дефолт — Input).","description":"Лист формы: значение из модели (`$model`) + опциональный компонент (`$component`, дефолт — Input).","params":[],"examplesCount":0,"topics":["overview","json-schema","validation"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json","usage":1},{"name":"JsonForm","kind":"interface","signature":"export interface JsonForm<T> extends CoreForm<T> {\\n /** Та же JSON-схема, из которой собраны model+form (рендерер строит из неё render-дерево). */\\n schema: JsonFormSchema<T>;\\n /** Реестр компонентов/source (нужен рендереру для резолва имён). */\\n registry: ComponentRegistry;\\n /**\\n * Render-behavior, собранный фабрикой из конфига. В отличие от React-варианта он ещё НЕ применён:\\n * дерево строит сам рендерер, он же и накладывает поведение. Ссылка стабильна — бандл собран один\\n * раз, поэтому рендерер не пересобирает дерево на каждый рендер.\\n */\\n renderBehavior?: RenderBehaviorFn<T>;\\n}","summary":"Собранная форма из JSON-схемы: источник истины для `<JsonFormRenderer form={…} />`.","description":"Собранная форма из JSON-схемы: источник истины для `<JsonFormRenderer form={…} />`.","params":[],"examplesCount":0,"sourcePath":"src/create-json-form.ts","entries":["."],"package":"@reformer/renderer-json","usage":4},{"name":"JsonFormRenderer","kind":"function","signature":"export function JsonFormRenderer<T>({\\n form,\\n schema: schemaProp,\\n model: modelProp,\\n registry: registryProp,\\n renderBehavior: renderBehaviorProp,\\n onSchemaReady,\\n validateSchema = false,\\n}: JsonFormRendererProps<T>): ReactNode","summary":"Главный компонент пакета.","description":"Главный компонент пакета. Рендерит форму, описанную JSON-схемой.\\n\\nДолжен использоваться внутри {@link JsonRendererProvider}, который снабжает рендерер\\nреестром компонентов. Без реестра компонент бросит исключение при попытке резолва.","params":[],"example":"Форма из JSON-схемы (M1)\\n```tsx\\nimport { useMemo } from \'react\';\\nimport { createModel } from \'@reformer/core\';\\nimport { Input, Box, FormField } from \'@reformer/ui-kit\';\\nimport {\\nJsonFormRenderer,\\nJsonRendererProvider,\\ndefineRegistry,\\nFIELD_WRAPPER,\\ntype JsonFormSchema,\\n} from \'@reformer/renderer-json\';\\n\\n// Привязки — строки-операторы: \'$model(...)\', \'$component(...)\', \'$dataSource(...)\'.\\nconst schema: JsonFormSchema = {\\nversion: \'1.0\',\\nroot: {\\ncomponent: \'$component(Box)\',\\nchildren: [\\n{\\nvalue: \'$model(email)\',\\ncomponent: \'$component(Input)\',\\ncomponentProps: { label: \'Email\' },\\n},\\n],\\n},\\n};\\n\\ntype MyForm = { email: string };\\n\\nfunction MyFormPage() {\\n// M1: модель — источник истины значений; листья схемы биндятся к её сигналам.\\nconst model = useMemo(() => createModel<MyForm>({ email: \'\' }), []);\\nconst registry = useMemo(() => defineRegistry((reg) => {\\nreg.component(\'Input\', Input);\\nreg.component(\'Box\', Box);\\nreg.component(FIELD_WRAPPER, FormField); // системная обёртка полей\\n}), []);\\n\\n// Реестр — глобальная настройка через провайдер; модель — per-form проп рендерера.\\nreturn (\\n<JsonRendererProvider settings={{ registry }}>\\n<JsonFormRenderer<MyForm> schema={schema} model={model} validateSchema={import.meta.env.DEV} />\\n</JsonRendererProvider>\\n);\\n}\\n```\\n\\n**Note**: `JsonFormRenderer` принимает `{ schema, model, renderBehavior?, onSchemaReady?, validateSchema? }`.\\nПод M1 модель (`FormModel`) обязательна и передаётся пропом `model` — это per-form состояние;\\nлистья JSON-схемы биндятся к её сигналам конвертером {@link createRenderSchemaFromJsonM1}.","examplesCount":1,"topics":["overview","json-schema","troubleshooting","cookbook","validation","form-wizard","i18n"],"sourcePath":"src/components/json-form-renderer.tsx","entries":["."],"package":"@reformer/renderer-json","usage":7},{"name":"JsonFormRendererProps","kind":"interface","signature":"export interface JsonFormRendererProps<T> {\\n /**\\n * Собранный бандл {@link createJsonForm}. Если задан — поставляет `schema`, `model`, `registry`\\n * и `renderBehavior` (передавать их отдельно не нужно). Иначе укажи `schema` + `model`.\\n */\\n form?: JsonForm<T>;\\n /**\\n * JSON-схема формы. См. {@link JsonFormSchema}. Опционально, если задан `form`. Тип намеренно\\n * НЕ параметризован `T`: рендерер принимает любую схему (в т.ч. `.json`-импорт «строкой с сервера»);\\n * типобезопасность путей `$model(...)` даётся на этапе авторинга (`defineJsonSchema<T>`/`createJsonForm<T>`).\\n */\\n schema?: JsonFormSchema;\\n /**\\n * Модель данных формы (M1). Листья схемы (`value: \'$model(path)\'`) биндятся к её сигналам\\n * (`model.signalAt(path)`) конвертером {@link createRenderSchemaFromJsonM1}. Per-form состояние,\\n * поэтому передаётся пропом рендерера (не глобальными настройками {@link JsonRendererProvider}).\\n * Опционально, если задан `form`.\\n */\\n model?: FormModel<T>;\\n /**\\n * Реестр компонентов. Приоритет: `registry` → `form.registry` → контекст\\n * {@link JsonRendererProvider}.\\n *\\n * Нужен, когда провайдер и рендерер оказываются в РАЗНЫХ бандлах (микрофронты): React-контекст\\n * границу бандла не пересекает, поэтому провайдер хоста невидим рендереру из ремоута. В прод-сборке\\n * такой отказ МОЛЧАЛИВЫЙ — DEV-guard в `useJsonRendererSettings` вырезается при сборке пакета.\\n * Проп убирает эту точку отказа: реестр передаётся напрямую, провайдер становится необязательным.\\n */\\n registry?: ComponentRegistry;\\n /**\\n * Behavior поверх готовой схемы: hideWhen/patchProps/onComponentEvent. Приоритет: этот проп →\\n * `form.renderBehavior` (собранный фабрикой). Ссылка обязана быть стабильной — см. dev-предупреждение\\n * ниже по файлу.\\n */\\n renderBehavior?: RenderBehaviorFn<T>;\\n /** Колбэк, получающий построенный `RenderSchemaProxy` для внешних манипуляций. */\\n onSchemaReady?: (schema: RenderSchemaProxy<T>) => void;\\n /**\\n * Валидировать JSON-схему против мета-схемы перед рендером. При ошибках рисует\\n * {@link SchemaErrorPanel} вместо формы. ajv грузится **динамически** (`import(\'../validate\')`) —\\n * в prod-бандл не попадает, пока `validateSchema` не включён.\\n *\\n * По умолчанию `false`. Чтобы валидировать только в dev, приложение передаёт значение из\\n * СВОЕГО окружения: `validateSchema={import.meta.env.DEV}` — детекцию dev нельзя «запечь» в пакет,\\n * т.к. `import.meta.env.DEV` инлайнится в `false` при production-сборке самого пакета.\\n */\\n validateSchema?: boolean;\\n}","summary":"Props of {@link JsonFormRenderer}.","description":"Props of {@link JsonFormRenderer}.","params":[],"examplesCount":0,"sourcePath":"src/components/json-form-renderer.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonFormSchema","kind":"interface","signature":"export interface JsonFormSchema<T = unknown> {\\n /**\\n * Путь к мета-схеме для IDE (VSCode подсветит структуру/синтаксис/имена `$component`).\\n * Игнорируется конвертером. Сгенерировать конкретную мета-схему: `gen-form-json-schema.ts`.\\n */\\n $schema?: string;\\n /** Идентификатор схемы (произвольная строка: для реестров/трекинга). Игнорируется конвертером. */\\n id?: string;\\n /** Версия схемы (для миграций). */\\n version?: string;\\n /** Метаданные схемы (имя/описание — для каталогов/UI). Игнорируется конвертером. */\\n meta?: {\\n name?: string;\\n description?: string;\\n };\\n /** Корневой узел. С типом `T` пути `$model(...)` в дереве сужаются до {@link Path}<T>. */\\n root: JsonNode<T>;\\n}","summary":"Корневая JSON-схема формы.","description":"Корневая JSON-схема формы.","params":[],"example":"```ts\\nconst schema: JsonFormSchema = {\\n version: \'1.0\',\\n root: {\\n component: \'$component(Box)\',\\n children: [{ value: \'$model(email)\', component: \'$component(Input)\' }],\\n },\\n};\\n```","examplesCount":1,"topics":["overview","json-schema","cookbook","validation"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json","usage":15},{"name":"JsonNode","kind":"type","signature":"export type JsonNode<T = unknown> = JsonFieldNode<T> | JsonArrayNode<T> | JsonContainerNode<T>;","summary":"Узел JSON-схемы (M1).","description":"Узел JSON-схемы (M1). `T` — форма модели: при указании `$model(...)` пути сужаются до {@link Path}<T>.","params":[],"examplesCount":0,"topics":["overview","json-schema","troubleshooting","cookbook","validation"],"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonOperator","kind":"type","signature":"export type JsonOperator = ModelOp | ComponentOp | HtmlOp | DataSourceOp | FnOp | LocaleOp;","summary":"Любой строковый оператор JSON-схемы.","description":"Любой строковый оператор JSON-схемы.","params":[],"examplesCount":0,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonRendererProvider","kind":"function","signature":"export function JsonRendererProvider({ settings, children }: JsonRendererProviderProps): ReactNode","summary":"Провайдер настроек для {@link JsonFormRenderer}.","description":"Провайдер настроек для {@link JsonFormRenderer}. Прокидывает реестр и\\nfieldWrapper во вложенные компоненты через React Context.\\n\\nПоддерживает вложенность: внутренний провайдер сливается с внешним. При дублях имён\\nвыигрывает **внутренний** (последний), как у `Object.assign` — внешний задаёт базу,\\nвнутренний её перекрывает. Программный аналог без React — {@link composeRegistries}.","params":[],"example":"M1: реестр через settings (глобально), модель — пропом рендерера (per-form)\\n```tsx\\n// Модель — источник истины (M1); листья схемы биндятся к её сигналам.\\nconst model = useMemo(() => createModel<MyForm>({ email: \'\' }), []);\\nconst registry = useMemo(() => defineRegistry((reg) => {\\nreg.component(\'Input\', Input);\\nreg.component(FIELD_WRAPPER, FormField);\\n}), []);\\n\\n<JsonRendererProvider settings={{ registry }}>\\n<JsonFormRenderer<MyForm> schema={schema} model={model} />\\n</JsonRendererProvider>\\n```","examplesCount":1,"topics":["overview","json-schema","registry","troubleshooting","cookbook","i18n"],"sourcePath":"src/context/json-renderer-context.tsx","entries":["."],"package":"@reformer/renderer-json","usage":11},{"name":"JsonRendererProviderProps","kind":"interface","signature":"export interface JsonRendererProviderProps {\\n /** Настройки рендерера, как минимум содержащие `registry`. */\\n settings: JsonRendererSettings;\\n /** Дочернее поддерево, в котором доступен `JsonFormRenderer` и `useJsonRendererSettings`. */\\n children: ReactNode;\\n}","summary":"Props {@link JsonRendererProvider}.","description":"Props {@link JsonRendererProvider}.","params":[],"examplesCount":0,"sourcePath":"src/context/json-renderer-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonRendererSettings","kind":"interface","signature":"export interface JsonRendererSettings extends RendererSettings {\\n /** Реестр компонентов и source-значений. См. {@link defineRegistry}. */\\n registry?: ComponentRegistry;\\n}","summary":"Расширенные настройки рендерера: всё из `RendererSettings` плюс реестр.","description":"Расширенные настройки рендерера: всё из `RendererSettings` плюс реестр.\\n\\nЭто **глобальные** настройки, общие на всё поддерево (реестр компонентов, `fieldWrapper`,\\n`resolveFieldAdapter`). Модель данных сюда не входит — она per-form и передаётся пропом\\n`model` компонента {@link JsonFormRenderer}.","params":[],"examplesCount":0,"topics":["overview","registry","cookbook"],"sourcePath":"src/context/json-renderer-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"JsonTextChild","kind":"type","signature":"export type JsonTextChild = string | number;","summary":"Текстовая часть содержимого — элемент `children`, не являющийся узлом.","description":"Текстовая часть содержимого — элемент `children`, не являющийся узлом. Строки могут быть\\nоператорами: `\'$model(path)\'` даёт реактивное значение модели, `\'$locale(key)\'` — строку\\nлокализации, остальные строки — литералы. Соседние части склеиваются без разделителя.","params":[],"example":"```json\\n{ \\"component\\": \\"$html(p)\\", \\"children\\": [\\"Платёж: \\", \\"$model(monthlyPayment)\\", \\" ₽\\"] }\\n```","examplesCount":1,"sourcePath":"src/types/json-schema.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"LOCALE_SERVICE","kind":"const","signature":"export const LOCALE_SERVICE","summary":"Зарезервированный ключ реестра для единственного сервиса локализации.","description":"Зарезервированный ключ реестра для единственного сервиса локализации.\\n\\n`reg.locale(...)` кладёт сервис под этот ключ; оператор `\\"$locale(key)\\"` резолвится через него\\n(`registry.getLocale()`). Ключ намеренно отличается от имени оператора, чтобы `$dataSource`/`$fn`\\nне могли достать сервис локализации по имени.","params":[],"example":"```typescript\\nimport { defineRegistry, createLocaleResolver } from \'@reformer/renderer-json\';\\n\\nconst registry = defineRegistry((reg) => {\\n reg.locale(createLocaleResolver({ \'fields.email.label\': \'Email\' }));\\n});\\n```","examplesCount":1,"topics":["registry"],"sourcePath":"src/registry/constants.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleOp","kind":"type","signature":"export type LocaleOp = `$locale(${string})`;","summary":"Строка-оператор ссылки на ключ локализации: `` `$locale(${key})` ``.","description":"Строка-оператор ссылки на ключ локализации: `` `$locale(${key})` ``.","params":[],"examplesCount":0,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleParams","kind":"type","signature":"export type LocaleParams = Record<string, unknown>;","summary":"Параметры для интерполяции/склонения (ICU-values, i18next-values и т.п.).","description":"Параметры для интерполяции/склонения (ICU-values, i18next-values и т.п.).","params":[],"examplesCount":0,"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleProvider","kind":"function","signature":"export function LocaleProvider({ service, children }: LocaleProviderProps): ReactNode","summary":"Провайдер сервиса локализации для реактивного пути.","description":"Провайдер сервиса локализации для реактивного пути. Оберни форму (или её часть) и передавай\\nновый `service` при смене языка — вложенные `I18n` перерисуются без пересборки схемы.","params":[],"example":"Переключение языка\\n```tsx\\nimport { LocaleProvider, createLocaleService, JsonFormRenderer } from \'@reformer/renderer-json\';\\n\\nconst services = { ru: createLocaleService(ruTable), en: createLocaleService(enTable) };\\nfunction App() {\\nconst [lang, setLang] = useState<\'ru\' | \'en\'>(\'ru\');\\nreturn (\\n<LocaleProvider service={services[lang]}>\\n<JsonFormRenderer schema={schema} />\\n</LocaleProvider>\\n);\\n}\\n```","examplesCount":1,"topics":["json-schema","registry","i18n"],"sourcePath":"src/locale/locale-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleProviderProps","kind":"interface","signature":"export interface LocaleProviderProps {\\n /** Текущий сервис локализации. Смена ссылки (напр. при переключении языка) перерендеривает все `I18n`. */\\n service: LocaleService;\\n /** Поддерево, в котором `I18n`/`useLocale` видят этот сервис. */\\n children: ReactNode;\\n}","summary":"Props {@link LocaleProvider}.","description":"Props {@link LocaleProvider}.","params":[],"examplesCount":0,"sourcePath":"src/locale/locale-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleResolver","kind":"type","signature":"export type LocaleResolver = (key: string, params?: LocaleParams) => string;","summary":"Резолвер ключа (+опциональные параметры) в строку.","description":"Резолвер ключа (+опциональные параметры) в строку.","params":[],"examplesCount":0,"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"LocaleService","kind":"interface","signature":"export interface LocaleService {\\n /** Ключ (+params) → локализованная строка (при промахе — сам ключ). Для label/placeholder и fallback `Trans`. */\\n resolve: LocaleResolver;\\n /**\\n * Ключ (+params) → rich-контент (markdown/JSX). Опционален. Используется `Trans`/`RichText`, когда\\n * нужен не голый текст, а разметка. Реализуется потребителем (напр. через `react-markdown`).\\n */\\n render?(key: string, params?: LocaleParams): ReactNode;\\n /** Множество известных ключей. Есть → `validate` ловит `unknown locale key`; нет → проверка мягко пропускается (как для `$model`). */\\n keys?: readonly string[];\\n}","summary":"Сервис локализации в реестре / контексте.","description":"Сервис локализации в реестре / контексте. `resolve` обязателен (строковый путь); `render`\\nопционален (rich/markdown-путь через `Trans`/`RichText`); `keys` (если задан — напр., из каталога)\\nвключает проверку опечаток ключей на этапе `validateFormSchema`.","params":[],"examplesCount":0,"topics":["registry","i18n"],"sourcePath":"src/locale/locale-service.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ModelOp","kind":"type","signature":"export type ModelOp<T = unknown> = `$model(${Path<T>})`;","summary":"Строка-оператор привязки к полю/массиву модели: `` `$model(${path})` ``.","description":"Строка-оператор привязки к полю/массиву модели: `` `$model(${path})` ``.\\n\\nПараметризуется формой модели `T`: при `ModelOp<CreditForm>` путь сужается до {@link Path}<T>\\n(опечатка `$model(loanTyp)` — ошибка компиляции). Без параметра (`ModelOp`) — `T = unknown`,\\nпуть = любая строка (обратная совместимость и схема-строкой-с-сервера).","params":[],"examplesCount":0,"topics":["overview","json-schema"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"OperatorNames","kind":"interface","signature":"export interface OperatorNames {\\n /** Имена из `$component(...)`. */\\n components: string[];\\n /** Имена из `$dataSource(...)`. */\\n dataSources: string[];\\n /** Имена из `$fn(...)`. */\\n fns: string[];\\n /** Ключи из `$locale(...)`. */\\n locales: string[];\\n}","summary":"Имена, к которым схема обращается через операторы.","description":"Имена, к которым схема обращается через операторы.","params":[],"examplesCount":0,"sourcePath":"src/collect-operator-names.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"ParsedOperator","kind":"interface","signature":"export interface ParsedOperator {\\n op: \'model\' | \'component\' | \'html\' | \'dataSource\' | \'fn\' | \'locale\';\\n arg: string;\\n}","summary":"Разобранный оператор: тип + аргумент (путь/имя/ключ/тег).","description":"Разобранный оператор: тип + аргумент (путь/имя/ключ/тег).","params":[],"examplesCount":0,"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"parseOperator","kind":"function","signature":"export function parseOperator(value: unknown): ParsedOperator | null","summary":"Разбор строки-оператора `\\"$op(arg)\\"`.","description":"Разбор строки-оператора `\\"$op(arg)\\"`. Возвращает `null` для не-операторов (обычных строк),\\nчтобы вызывающий оставил значение как есть.","params":[["value","- Проверяемое значение (не-строки сразу дают `null`)."]],"returns":"","example":"```ts\\nparseOperator(\'$model(loanType)\'); // { op: \'model\', arg: \'loanType\' }\\nparseOperator(\'$dataSource(LOAN_TYPES)\'); // { op: \'dataSource\', arg: \'LOAN_TYPES\' }\\nparseOperator(\'Введите сумму\'); // null (обычная строка)\\n```","examplesCount":1,"topics":["overview"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"Path","kind":"type","signature":"export type Path<T> = unknown extends T ? string : PathImpl<T>;","summary":"Все точечные пути к полям формы `T` (`\'loanType\'`, `\'personalData.firstName\'`, `\'items.0.amount\'`).","description":"Все точечные пути к полям формы `T` (`\'loanType\'`, `\'personalData.firstName\'`, `\'items.0.amount\'`).\\nДля `unknown`/`any` (схема пришла строкой с сервера — тип формы неизвестен) деградирует в `string`,\\nпоэтому нетипизированный сценарий продолжает работать как раньше.","params":[],"examplesCount":0,"topics":["overview","cookbook"],"sourcePath":"src/operators.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"RegistryBuilder","kind":"interface","signature":"export interface RegistryBuilder {\\n /**\\n * Зарегистрировать React-компонент под именем — доступен в схеме как\\n * `$component(name)`. Одним методом регистрируются и компоненты-листья\\n * (Input/Select), и контейнеры (Box/Section/FormField): роль узла (лист vs\\n * контейнер) определяется структурой узла схемы (`value` vs `children`),\\n * а не регистрацией.\\n */\\n component<P>(name: string, component: ComponentType<P>, description?: string): void;\\n dataSource<T>(name: string, value: T, description?: string): void;\\n /**\\n * Зарегистрировать функцию под именем — доступна в схеме как `$fn(name)` (форматтеры,\\n * компараторы, `itemLabel`, обработчики). Отдельный от `dataSource` вид: бросает при регистрации,\\n * если передана не функция, и `validateFormSchema` отклоняет перепутанные `$fn`/`$dataSource`.\\n */\\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\\n fn<F extends (...args: any[]) => any>(name: string, fn: F, description?: string): void;\\n /**\\n * Зарегистрировать единственный сервис локализации для оператора `$locale(key)`. Принимает\\n * {@link LocaleService} (каталог через `createLocaleResolver` — включает validate-time проверку\\n * ключей) либо голый резолвер `(key) => string`. Кладётся под зарезервированный ключ `LOCALE_SERVICE`.\\n */\\n locale(service: LocaleService | LocaleResolver, description?: string): void;\\n}","summary":"Builder, который попадает в callback {@link defineRegistry}.","description":"Builder, который попадает в callback {@link defineRegistry}.","params":[],"example":"```typescript\\ndefineRegistry((reg: RegistryBuilder) => {\\n reg.component(\'Input\', Input);\\n reg.component(\'Box\', Box);\\n reg.dataSource(\'LOAN_TYPES\', LOAN_TYPES);\\n reg.fn(\'formatCurrency\', formatCurrency);\\n reg.locale(createLocaleResolver({ \'fields.email.label\': \'Email\' }));\\n});\\n```","examplesCount":1,"sourcePath":"src/registry/types.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"sanitizeHtmlProps","kind":"function","signature":"export function sanitizeHtmlProps(\\n props: Record<string, unknown> | undefined,\\n tag: string\\n): Record<string, unknown> | undefined","summary":"Чистит props HTML-узла: убирает `dangerouslySetInnerHTML`, обработчики `on*` и URL-атрибуты с исполняемой схемой.","description":"Чистит props HTML-узла: убирает `dangerouslySetInnerHTML`, обработчики `on*` и URL-атрибуты\\nс исполняемой схемой. Возвращает НОВЫЙ объект (исходный не мутируется); если чистить нечего —\\nисходную ссылку.\\n\\nОбработчики выкидываются, а не пропускаются: из JSON они приходят строками, React такой проп\\nмолча проигнорирует с предупреждением, но `$fn(...)`-резолв мог бы подставить туда и функцию —\\nа исполняемое поведение недоверенной разметке не положено.","params":[["props","- `componentProps` html-узла (уже после резолва операторов)."],["tag","- Тег узла — только для текста предупреждения."]],"returns":"Очищенные props.","example":"```ts\\nsanitizeHtmlProps({ className: \'p-4\', href: \'javascript:alert(1)\' }, \'a\');\\n// → { className: \'p-4\' } + console.warn\\n```","examplesCount":1,"sourcePath":"src/html/html-tags.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"SchemaErrorBoundary","kind":"class","signature":"export class SchemaErrorBoundary extends Component<\\n SchemaErrorBoundaryProps,\\n SchemaErrorBoundaryState\\n> { /* … */ }","summary":"","params":[],"examplesCount":0,"topics":["troubleshooting"],"sourcePath":"src/components/schema-error-boundary.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"SchemaErrorBoundaryProps","kind":"interface","signature":"export interface SchemaErrorBoundaryProps {\\n /** Поддерево рендера формы (обычно `<FormRenderer />`). */\\n children: ReactNode;\\n /**\\n * Ключ сброса: при изменении (новая схема/модель → новый `schemaProxy`) boundary забывает прошлую\\n * ошибку и пробует отрисовать заново. Иначе React держит error-состояние до размонтирования.\\n */\\n resetKey?: unknown;\\n /**\\n * Своя отрисовка ошибки вместо {@link SchemaErrorPanel}.\\n *\\n * Нужна потребителям, которые монтируют форму по данным извне (реестр форм, схема из сети):\\n * там уместнее показать доменную панель с кнопкой повтора и идентификатором формы, чем\\n * техническую подсказку про мета-схему.\\n */\\n fallback?: (error: Error) => ReactNode;\\n}","summary":"Props of {@link SchemaErrorBoundary}.","description":"Props of {@link SchemaErrorBoundary}.","params":[],"examplesCount":0,"sourcePath":"src/components/schema-error-boundary.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"SchemaErrorPanel","kind":"function","signature":"export function SchemaErrorPanel({ errors }: SchemaErrorPanelProps): ReactNode","summary":"Список ошибок схемы (path + message), с пометкой источника.","description":"Список ошибок схемы (path + message), с пометкой источника. Без внешних UI-зависимостей\\n(инлайн-стили), помечен `role=\\"alert\\"` и `data-testid=\\"schema-error-panel\\"`.\\n\\nОбычно рендерится автоматически внутри {@link JsonFormRenderer} (при `validate` и невалидной\\nсхеме). Можно использовать напрямую для показа результата `validateFormSchema().errors`.","params":[["props","- {@link SchemaErrorPanelProps} (массив `errors`)."]],"returns":"Панель со списком ошибок.","example":"Показать ошибки валидации схемы вручную\\n```tsx\\nimport { validateFormSchema } from \'@reformer/renderer-json/validate\';\\n\\nconst { valid, errors } = validateFormSchema(schema, { registry });\\nif (!valid) return <SchemaErrorPanel errors={errors} />;\\n```","examplesCount":1,"topics":["overview","troubleshooting","cookbook"],"sourcePath":"src/components/schema-error-panel.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"SchemaErrorPanelProps","kind":"interface","signature":"export interface SchemaErrorPanelProps {\\n /** Человекочитаемые ошибки (`validateFormSchema().errors`). */\\n errors: string[];\\n}","summary":"Props of {@link SchemaErrorPanel}.","description":"Props of {@link SchemaErrorPanel}.","params":[],"examplesCount":0,"sourcePath":"src/components/schema-error-panel.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"stripDocExtensions","kind":"function","signature":"export function stripDocExtensions<T>(schema: T): T","summary":"Рекурсивно вырезает `x-*`-ключи (`x-doc`/`x-runtimeProps`/`x-registryName`) из схемы.","description":"Рекурсивно вырезает `x-*`-ключи (`x-doc`/`x-runtimeProps`/`x-registryName`) из схемы. Нужно перед\\nкомпиляцией ajv: в strict-режиме ajv бросает `unknown keyword: \\"x-doc\\"`. Удачно — это машинная\\nгарантия, что валидатор DSL физически не видит doc-метаданные.","params":[["schema","- Любой JSON-совместимый узел (объект/массив/скаляр)."]],"returns":"Глубокая копия без `x-*`-ключей.","examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"toComponentPropsValidatorSchema","kind":"function","signature":"export function toComponentPropsValidatorSchema(\\n propsSchema: ComponentPropsSchema\\n): Record<string, unknown>","summary":"Превращает схему `componentProps` компонента ({@link ComponentPropsSchema}) в самодостаточную ajv-схему: {@link stripDocExtensions} (снять `x-*`) → {@link allowOperatorStrings} (обернуть пропы в `anyOf` с operatorOp) → добавить `definitions.operatorOp`, чтобы `$ref` резолвился при standalone-компиля","description":"Превращает схему `componentProps` компонента ({@link ComponentPropsSchema}) в самодостаточную\\najv-схему: {@link stripDocExtensions} (снять `x-*`) → {@link allowOperatorStrings} (обернуть пропы\\nв `anyOf` с operatorOp) → добавить `definitions.operatorOp`, чтобы `$ref` резолвился при\\nstandalone-компиляции. Используется фазой (d) `validateFormSchema` и IDE-веткой\\n{@link buildFormSchemaMetaSchema}.","params":[["propsSchema","- Полная схема componentProps (враппер + вариант; уже прошедшая mergeFieldPropsSchema)."]],"returns":"JSON-схема, готовая к `ajv.compile`.","examplesCount":0,"sourcePath":"src/schema/index.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"unwrapSignalValues","kind":"function","signature":"export function unwrapSignalValues(values?: LocaleParams): LocaleParams | undefined","summary":"Разворачивает значения-сигналы в обычные (читает `.value`), литералы отдаёт как есть.","description":"Разворачивает значения-сигналы в обычные (читает `.value`), литералы отдаёт как есть. Если сигналов\\nне было — возвращает исходный объект (стабильная ссылка). Pure — тестируется без DOM.","params":[],"examplesCount":0,"sourcePath":"src/locale/use-signal-value.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"useJsonForm","kind":"const","signature":"export const useJsonForm","summary":"Хук стабильной сборки формы: фабрика вызывается РОВНО один раз (ленивый инициализатор `useState`), поэтому model/form переживают ре-рендеры.","description":"Хук стабильной сборки формы: фабрика вызывается РОВНО один раз (ленивый инициализатор `useState`),\\nпоэтому model/form переживают ре-рендеры. `useMemo` для этого не годится — React вправе сбросить\\nего кэш и пересоздать форму (потеря введённого). Живая валидация армируется в эффекте.\\n\\nЭто общий хук семейства (`useFormBundle` из `@reformer/core`) под именем JSON-слоя: он не сужает\\nрезультат до `JsonForm<T>`, поэтому расширенные бандлы (со своими полями) переживают его без\\nпотерь.","params":[["factory","- Фабрика бандла (обычно `() => createJsonForm<T>({…})`)."]],"returns":"Стабильный бандл.","example":"```tsx\\nconst jsonForm = useJsonForm(() => createJsonForm<MyForm>({ schema, registry, initial }));\\n```","examplesCount":1,"topics":["overview","cookbook","review-checklist"],"sourcePath":"src/create-json-form.ts","entries":["."],"package":"@reformer/renderer-json","usage":9},{"name":"useJsonRendererSettings","kind":"function","signature":"export function useJsonRendererSettings(): JsonRendererSettings","summary":"Хук для чтения текущих настроек {@link JsonRendererProvider}.","description":"Хук для чтения текущих настроек {@link JsonRendererProvider}.\\n\\nВ режиме разработки бросает исключение, если вызван вне провайдера или\\nесли в провайдере не передан `registry`.","params":[],"returns":"Текущие {@link JsonRendererSettings}.","example":"```tsx\\nfunction MyControl() {\\n const { registry } = useJsonRendererSettings();\\n return <span>{registry?.has(\'Input\') ? \'ready\' : \'not registered\'}</span>;\\n}\\n```","examplesCount":1,"topics":["overview","troubleshooting"],"sourcePath":"src/context/json-renderer-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"useJsonRendererSettingsUnchecked","kind":"function","signature":"export function useJsonRendererSettingsUnchecked(): JsonRendererSettings","summary":"Настройки БЕЗ DEV-guard на наличие реестра.","description":"Настройки БЕЗ DEV-guard на наличие реестра.\\n\\nДля потребителей, которые получают реестр другим каналом (проп `registry` у\\n{@link JsonFormRenderer}, программная {@link composeRegistries}) и вправе обходиться без\\nпровайдера. Ключевой случай — микрофронты: React-контекст не пересекает границу бандла,\\nпоэтому провайдер хоста невидим рендереру из ремоута, и обязательный guard ломал бы\\nполностью рабочую конфигурацию. Проверку наличия реестра делает вызывающий.","params":[],"returns":"Текущие {@link JsonRendererSettings} как есть (возможно, пустые).","examplesCount":0,"sourcePath":"src/context/json-renderer-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"useLocale","kind":"function","signature":"export function useLocale(): LocaleService","summary":"Текущий сервис локализации из {@link LocaleProvider}.","description":"Текущий сервис локализации из {@link LocaleProvider}. Без провайдера — fallback-to-key.\\nИспользуется внутри {@link I18n}; вызывай напрямую для собственного localized-компонента.","params":[],"returns":"Активный {@link LocaleService}.","examplesCount":0,"sourcePath":"src/locale/locale-context.tsx","entries":["."],"package":"@reformer/renderer-json"},{"name":"useSignalValues","kind":"function","signature":"export function useSignalValues(values?: LocaleParams): LocaleParams | undefined","summary":"Реактивно разворачивает `values`-сигналы.","description":"Реактивно разворачивает `values`-сигналы. Перерендер компонента при изменении любого сигнала;\\nлитералы проходят как есть. Снапшот кэшируется (стабильная ссылка при неизменных значениях) —\\nиначе `useSyncExternalStore` зациклится.","params":[["values","- Параметры сообщения (сигналы и/или литералы)."]],"returns":"Развёрнутые значения для передачи в `LocaleService.resolve/render`.","examplesCount":0,"sourcePath":"src/locale/use-signal-value.ts","entries":["."],"package":"@reformer/renderer-json"},{"name":"validateFormSchema","kind":"function","signature":"export function validateFormSchema(\\n schema: unknown,\\n opts: ValidateFormSchemaOptions = {}\\n): FormSchemaValidationResult","summary":"Валидирует form-DSL JSON-схему.","description":"Валидирует form-DSL JSON-схему. Если передан `registry`, имена компонентов/source берутся из него\\n(иначе можно задать `componentNames`/`dataSourceNames` явно). Тянет `ajv` — живёт в subpath\\n`@reformer/renderer-json/validate`, чтобы не попадать в основной render-бандл.\\n\\nЕсли задан `opts.propSchemas` (карта регистр-имя → схема componentProps), дополнительно запускается\\nфаза (d): рекурсивный обход валидирует `componentProps` каждой компонент-ноды по её схеме (ловит\\nопечатки в именах пропов и неверные типы). Не задан → фаза не запускается (обратная совместимость).","params":[["schema","- Проверяемая JSON-схема (обычно {@link JsonFormSchema}, но принимает `unknown`)."],["opts","- {@link ValidateFormSchemaOptions}: `registry` либо явные списки имён; опц. `propSchemas`."]],"returns":"","example":"```ts\\nconst { valid, errors } = validateFormSchema(jsonSchema, { registry });\\nif (!valid) console.error(errors);\\n```","examplesCount":1,"topics":["overview","json-schema","registry","cookbook","validation","i18n"],"sourcePath":"src/validate.ts","entries":["./validate"],"package":"@reformer/renderer-json"},{"name":"ValidateFormSchemaOptions","kind":"interface","signature":"export interface ValidateFormSchemaOptions {\\n registry?: ComponentRegistry;\\n componentNames?: string[];\\n dataSourceNames?: string[];\\n /** Имена функций `reg.fn` для проверки `$fn(...)`. Не заданы → проверка `$fn`-имён пропускается. */\\n fnNames?: string[];\\n /** Ключи каталога локализации для проверки `$locale(...)`. Не заданы → проверка ключей пропускается. */\\n localeKeys?: readonly string[];\\n /**\\n * Карта регистр-имя → полная схема `componentProps` компонента (враппер + вариант, уже прошедшая\\n * `mergeFieldPropsSchema` у поставщика). Не задана → фаза (d) не запускается (мягкий пропуск, полная\\n * обратная совместимость). Компонент есть в дереве, но НЕ в карте → его props пропускаются\\n * индивидуально. Обычно берётся из `@reformer/ui-kit/meta` (`defaultPropSchemas`).\\n */\\n propSchemas?: Record<string, ComponentPropsSchema>;\\n}","summary":"Опции: реестр (имена извлекаются автоматически) либо явные списки имён/ключей.","description":"Опции: реестр (имена извлекаются автоматически) либо явные списки имён/ключей.","params":[],"examplesCount":0,"sourcePath":"src/validate.ts","entries":["./validate"],"package":"@reformer/renderer-json"}]},"@reformer/mcp":{"schemaVersion":1,"package":"@reformer/mcp","version":"6.0.0","topics":[{"id":"guide","file":"01-guide.md","title":"ReFormer MCP — start-here guide","purpose":"This MCP server gives you everything needed to build a form with the ReFormer library **from this server alone** — no need to read the library source. It exposes documentation (resources), lookup tools, and workflow prompts.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"How to use it (recommended order)","slug":"how-to-use-it-recommended-order"},{"heading":"What\'s where","slug":"what-s-where"},{"heading":"The 5 library packages (read their docs via resources)","slug":"the-5-library-packages-read-their-docs-via-resources"},{"heading":"Golden rules","slug":"golden-rules"}],"terms":[["the",24],["reformer",19],["schema",13],["validation",8],["json",8],["renderer",8],["docs",8],["form",7],["workflow",6],["model",6],["core",6],["guide",5],["this",5],["with",5],["from",5],["use",5],["add",5],["validate",5],["library",4],["read",4],["and",4],["for",4],["one",4],["react",4],["mcp",3],["server",3],["you",3],["resources",3],["prompts",3],["wizard",3],["render",3],["rules",3],["leaves",3],["value",3],["validators",3],["start",2],["here",2],["build",2],["source",2],["lookup",2],["tools",2],["get",2],["run",2],["prompt",2],["plan",2],["spec",2],["target",2],["behaviors",2],["self",2],["doc",2],["resource",2],["code",2],["example",2],["array",2],["cycle",2],["name",2],["exact",2],["createform",2],["validatemodel",2],["package",2],["when",2],["don",2],["review",2],["cross",2],["per",2],["packages",2],["cdk",2],["kit",2],["field",2],["operators",2],["path",2]]},{"id":"tools","file":"02-tools.md","title":"Tools","purpose":"Callable tools exposed by the server (use ListTools to enumerate at runtime). Names and arguments are exact.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"get_context","slug":"get-context"},{"heading":"choose_api","slug":"choose-api"},{"heading":"get_symbol_docs","slug":"get-symbol-docs"},{"heading":"find_recipe","slug":"find-recipe"},{"heading":"search_docs","slug":"search-docs"},{"heading":"list_symbols","slug":"list-symbols"},{"heading":"validate_form","slug":"validate-form"},{"heading":"plan_form","slug":"plan-form"},{"heading":"generate_form","slug":"generate-form"},{"heading":"report_issue","slug":"report-issue"}],"terms":[["the",19],["string",18],["optional",17],["reformer",13],["required",9],["package",9],["when",9],["json",8],["symbol",7],["kind",7],["and",6],["target",6],["core",6],["renderer",6],["one",6],["validation",6],["validate",6],["you",6],["use",5],["или",5],["full",5],["topic",5],["это",4],["choose_api",4],["когда",4],["for",4],["section",4],["with",4],["name",4],["layout",4],["server",3],["get_context",3],["оператор",3],["правила",3],["анти",3],["без",3],["react",3],["api",3],["поиск",3],["если",3],["правило",3],["символ",3],["требование",3],["enablewhen",3],["resetwhen",3],["onchange",3],["поле",3],["есть",3],["get_symbol_docs",3],["every",3],["example",3],["search",3],["all",3],["docs",3],["search_docs",3],["form",3],["copy",3],["behavior",3],["cross",3],["model",3],["schema",3],["проверки",3],["формы",3],["typescript",3],["intent",3],["cwd",3],["tools",2],["enumerate",2],["контекст",2],["под",2],["один",2],["шаг",2],["паттерны",2],["task",2],["своими",2],["словами",2],["русски",2],["английски",2],["тем",2],["задачи",2],["debug",2],["number",2],["жёсткий",2],["потолок",2],["перекрывает",2],["для",2],["замерено",2],["как",2],["first",2],["pass",2],["токенов",2],["сработало",2],["секциями",2],["будет",2],["честно",2],["этом",2],["какой",2],["похожих",2],["copyfrom",2],["validatewhen",2],["только",2],["возвращает",2],["задач",2],["description",2],["returns",2],["validatemodel",2],["code",2],["against",2],["find_recipe",2],["text",2],["fallback",2],["ranked",2],["resolve",2],["cycle",2],["sync",2],["fields",2],["can",2],["recipe",2],["slug",2],["uri",2],["know",2],["don",2],["surface",2],["всегда",2],["того",2],["живёт",2],["между",2],["собой",2],["каждый",2],["нет",2],["разбор",2],["plan_form",2],["описание",2],["formintent",2],["корня",2],["репозитория",2],["файлов",2],["свой",2],["fix",2],["report",2],["project",2],["root",2],["error",2],["runs",2]]},{"id":"prompts","file":"03-prompts.md","title":"Prompts","purpose":"Workflow prompts. Each returns an instruction message that orchestrates one step and points you at the resources/tools to read.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"start-here","slug":"start-here"},{"heading":"discover-context","slug":"discover-context"},{"heading":"plan-form","slug":"plan-form-2"},{"heading":"create-form","slug":"create-form"},{"heading":"add-feature","slug":"add-feature"},{"heading":"to-renderer","slug":"to-renderer"},{"heading":"review","slug":"review"}],"terms":[["the",19],["target",10],["and",9],["form",9],["renderer",9],["feature",7],["for",6],["add",6],["optional",6],["prompts",5],["you",5],["tool",5],["file",5],["code",5],["json",5],["prompt",4],["only",4],["layout",4],["then",4],["required",4],["returns",3],["read",3],["equivalent",3],["use",3],["start",3],["reformer",3],["same",3],["create",3],["review",3],["description",3],["projectpath",3],["when",3],["core",3],["spec",3],["wizard",3],["workflow",2],["that",2],["one",2],["step",2],["resources",2],["tools",2],["are",2],["agent",2],["not",2],["first",2],["this",2],["there",2],["its",2],["here",2],["resource",2],["guide",2],["discover",2],["context",2],["with",2],["plan",2],["arguments",2],["find_recipe",2],["behaviors",2],["reading",2],["which",2],["stack",2],["from",2],["react",2],["добавить",2],["форму",2],["validation",2],["behavior",2],["array",2],["формы",2],["аргументы",2],["схлопывает",2],["прежние",2],["четырёх",2]]},{"id":"resources","file":"04-resources.md","title":"Resources","purpose":"Documentation the server serves as MCP resources (ReadResource to fetch).","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"URI scheme","slug":"uri-scheme"},{"heading":"Self-documentation (this server)","slug":"self-documentation-this-server"},{"heading":"Library docs (the 5 packages)","slug":"library-docs-the-5-packages"},{"heading":"How this relates to tools","slug":"how-this-relates-to-tools"}],"terms":[["the",20],["reformer",20],["docs",18],["mcp",7],["section",7],["json",7],["full",6],["package",6],["sections",6],["resources",5],["catalog",5],["uris",5],["schema",5],["you",5],["guide",4],["form",4],["slug",4],["llms",4],["renderer",4],["when",4],["server",3],["returns",3],["and",3],["one",3],["every",3],["before",3],["search_docs",3],["read",3],["this",3],["self",3],["tools",3],["pkg",3],["cdk",3],["kit",3],["documentation",2],["uri",2],["not",2],["enumerate",2],["individual",2],["discover",2],["are",2],["doc",2],["workflow",2],["prompts",2],["resource",2],["its",2],["txt",2],["library",2],["core",2],["react",2],["whole",2],["from",2],["exact",2],["via",2],["examples",2],["slugs",2],["field",2],["render",2],["registry",2],["find_recipe",2],["same",2],["text",2],["want",2]]},{"id":"m1-workflow","file":"05-m1-workflow.md","title":"M1 form-building workflow","purpose":"The canonical order for building a ReFormer form (M1 = single reactive model is the source of truth). Follow it top to bottom. Each step lists the decision, the key API, and the traps the runtime would otherwise punish. Look up exact signatures with `get_symbol_docs`, worked examples with `find_recipe`.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"0. Choose the render target","slug":"choose-the-render-target"},{"heading":"1. Model — `createModel<T>(initial)`","slug":"model-createmodel-t-initial"},{"heading":"2. Schema — field leaves","slug":"schema-field-leaves"},{"heading":"3. Assemble — ONE call per target","slug":"assemble-one-call-per-target"},{"heading":"4. Validation — `defineValidationSchema` + `validateModel(model, schema)`","slug":"validation-definevalidationschema-validatemodel-model-schema"},{"heading":"5. Behaviors — reactive dynamics (optional)","slug":"behaviors-reactive-dynamics-optional"},{"heading":"6. Arrays & Wizard (when needed)","slug":"arrays-wizard-when-needed"},{"heading":"7. Render","slug":"render"},{"heading":"Checklist before you finish","slug":"checklist-before-you-finish"}],"terms":[["the",81],["model",59],["schema",33],["and",22],["value",20],["form",19],["email",17],["validation",17],["field",16],["renderer",16],["json",16],["step",15],["reformer",14],["from",14],["rules",12],["validatemodel",12],["not",11],["validators",11],["with",10],["null",10],["render",9],["core",9],["react",9],["are",9],["const",8],["signal",8],["own",8],["definevalidationschema",8],["cross",8],["find_recipe",7],["tree",7],["component",7],["array",7],["leaf",7],["bundle",7],["run",7],["validate",7],["promise",7],["for",6],["each",6],["per",6],["only",6],["import",6],["password",6],["fields",6],["boolean",6],["kit",5],["display",5],["registry",5],["factory",5],["initial",5],["item",5],["when",5],["behavior",5],["node",5],["its",5],["behaviors",5],["defineformbehavior",5],["sig",5],["validateasync",5],["required",5],["wizard",5],["key",4],["control",4],["layout",4],["string",4],["operators",4],["createmodel",4],["shape",4],["full",4],["optional",4],["regform",4],["separate",4],["inputfield",4],["never",4],["call",4],["you",4],["same",4],["over",4],["submit",4],["valid",4],["async",4],["scope",4],["schemas",4],["single",3],["target",3],["one",3],["formfield",3],["renderschema",3],["conditional",3],["all",3],["they",3],["differ",3],["calls",3],["values",3],["type",3],["arrays",3],["sub",3],["get",3],["leaves",3],["carries",3],["componentprops",3],["label",3],["don",3],["their",3],["config",3],["useformbundle",3],["reg",3],["validatestep",3],["validateall",3],["createjsonform",3],["return",3],["createform",3],["them",3],["cond",3],["inside",3],["root",3],["into",3],["that",3],["returns",3],["confirmpassword",3],["await",3],["returning",3],["via",3],["settings",3],["building",2],["reactive",2],["api",2],["traps",2],["plain",2],["data",2],["three",2],["steps",2],["which",2],["see",2],["items",2],["every",2],["has",2],["signals",2],["ones",2],["usememo",2],["age",2],["ambient",2],["old",2],["gone",2],["how",2],["createcoreform",2],["builder",2],["bound",2],["createreactform",2],["takes",2],["plus",2],["both",2],["runs",2],["input",2],["identity",2],["like",2],["bare",2],["validationerror",2],["runner",2],["superseded",2],["network",2],["failure",2],["true",2],["snapshot",2],["apply",2],["build",2],["factories",2],["now",2],["routes",2],["error",2],["false",2],["what",2],["minlength",2],["reads",2],["code",2],["message",2],["res",2],["taken",2],["trap",2],["modelvalidator",2],["errors",2],["nodes",2],["itself",2],["two",2],["dsl",2],["primitives",2],["assembly",2],["compute",2],["residence",2],["sameaddress",2],["check_behaviors",2],["tool",2],["cdk",2],["step_schemas",2],["fullschema",2],["without",2],["write",2],["name",2],["components",2]]},{"id":"form-directory-layout","file":"06-form-directory-layout.md","title":"Form directory layout (core / renderer-react / renderer-json)","purpose":"How to organize the files of one form. **Default = minimalist:** a flat set of files — one `index.tsx` component (ALL steps inline) plus one file per concern. Most files are **plain-named**; the **layer-variable** concerns — `schema` and `behavior`, plus the optional renderer-json wizard shim — carry a `form.` / `renderer.` prefix (dot) marking which layer they belong to. The base file set is otherwise **identical across `@reformer/core`, `@reformer/renderer-react`, and `@reformer/renderer-json`**. Scale up to the folder layout (§3) only for large forms. Use `[form-name]` / `[FormName]` as placeholders.","keyConcepts":[],"api":"","patterns":[],"antiPatterns":[],"examples":[],"troubleshooting":[],"seeAlso":[],"sections":[{"heading":"1. Minimalist (default) — flat, one file per concern","slug":"minimalist-default-flat-one-file-per-concern"},{"heading":"2. App-level infrastructure (renderer-json only) — recommendation, not a conformance bar","slug":"app-level-infrastructure-renderer-json-only-recommendation-not-a-conformance-bar"},{"heading":"3. Scale up: folders (large forms)","slug":"scale-up-folders-large-forms"},{"heading":"4. Scaling","slug":"scaling"},{"heading":"5. Configuring the default (`REFORMER_FORM_LAYOUT`)","slug":"configuring-the-default-reformer-form-layout"},{"heading":"6. Reuse map","slug":"reuse-map"}],"terms":[["the",88],["renderer",67],["schema",57],["form",50],["json",45],["behavior",29],["model",25],["tsx",23],["registry",23],["wizard",21],["and",20],["one",18],["data",18],["not",16],["reuse",16],["validation",15],["component",14],["file",14],["sources",13],["app",12],["index",11],["steps",11],["are",11],["layer",11],["base",11],["only",11],["react",10],["default",10],["per",10],["components",10],["that",10],["dsl",10],["all",9],["inline",9],["for",9],["this",9],["target",9],["meta",9],["step",9],["layout",8],["shim",8],["reformer",8],["render",8],["folders",8],["types",8],["never",7],["api",7],["when",7],["same",7],["level",7],["core",6],["files",6],["minimalist",6],["concern",6],["plain",6],["optional",6],["dot",6],["forms",6],["with",6],["from",6],["flat",5],["set",5],["формы",5],["names",5],["type",5],["submit",5],["raw",5],["kit",5],["directory",4],["plus",4],["variable",4],["across",4],["large",4],["name",4],["has",4],["guide",4],["see",4],["reformer_form_layout",4],["lib",4],["single",4],["whole",4],["field",4],["value",4],["inside",4],["variant",4],["keep",4],["its",4],["own",4],["src",4],["named",3],["concerns",3],["carry",3],["prefix",3],["which",3],["identical",3],["scale",3],["файлов",3],["contract",3],["values",3],["every",3],["below",3],["canonical",3],["example",3],["repository",3],["naming",3],["both",3],["module",3],["holds",3],["enums",3],["validatestep",3],["validateall",3],["options",3],["async",3],["loaders",3],["prefill",3],["prefixed",3],["rendernode",3],["tree",3],["literal",3],["itself",3],["jsx",3],["changes",3],["helper",3],["binds",3],["nothing",3],["exists",3],["validators",3],["into",3],["constants",3],["aspirational",3],["shared",3],["generated",3],["once",3],["create",3],["cross",3],["mcp",3],["env",3],["they",2],["folder",2],["use",2],["formname",2],["один",2],["initial",2],["dictionaries",2],["filename",2],["older",2],["directories",2],["references",2],["content",2],["leads",2],["configurable",2],["documents",2],["regardless",2],["everything",2],["lives",2],["rule",2],["two",2],["entry",2],["createjsonform",2],["option",2],["over",2],["datasources",2],["load",2],["formschema",2],["componentprops",2],["datasource",2],["definejsonschema",2],["contains",2],["personaldata",2],["server",2],["non",2],["else",2],["hidewhen",2],["targets",2],["navigation",2],["their",2],["does",2],["export",2],["application",2],["shape",2],["therefore",2],["allowed",2],["beyond",2],["sets",2],["docs",2],["llms",2],["typing",2],["rules",2],["nested",2],["sub",2],["address",2],["blocks",2],["separate",2],["derived",2],["domain",2],["split",2],["belongs",2],["these",2],["above",2],["conformance",2]]}],"symbols":[{"name":"BrowserKnowledge","kind":"interface","signature":"export interface BrowserKnowledge {\\n knowledge: Knowledge;\\n /** Накопленные отчёты — хост решает, сохранять ли их и куда. */\\n issues: MemoryIssueSink;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/platform/browser/knowledge.ts","entries":["./browser"],"package":"@reformer/mcp"},{"name":"BrowserKnowledgeInput","kind":"interface","signature":"export interface BrowserKnowledgeInput {\\n /** Индексы пакетов. Без них знание пустое: на индексе стоит почти каждый инструмент. */\\n index: IndexBundle;\\n /**\\n * Тексты `llms.txt`. Необязательны: `get_context`, `choose_api`, `get_symbol_docs`,\\n * `list_symbols` и `validate_form` работают на одном индексе, и потребителю, которому\\n * хватает их, незачем платить за 1.27 МБ прозы.\\n */\\n docs?: DocsBundle | null;\\n /** Спеки, уже прочитанные хостом: имя файла → текст. */\\n specs?: ReadonlyMap<string, string>;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/platform/browser/knowledge.ts","entries":["./browser"],"package":"@reformer/mcp"},{"name":"createBrowserKnowledge","kind":"function","signature":"export function createBrowserKnowledge(input: BrowserKnowledgeInput): BrowserKnowledge","summary":"","params":[],"examplesCount":0,"sourcePath":"src/platform/browser/knowledge.ts","entries":["./browser"],"package":"@reformer/mcp"},{"name":"createKnowledge","kind":"function","signature":"export function createKnowledge(sources: KnowledgeSources): Knowledge","summary":"Собрать знание из источников.","description":"Собрать знание из источников.\\n\\nИндекс сливается сразу — он нужен почти каждому инструменту, а слияние стоит около 17 мс\\nпротив 784 мс у прежнего разбора AST. Документация читается лениво: до первого обращения\\nона может не понадобиться вовсе.","params":[],"examplesCount":0,"sourcePath":"src/core/knowledge.ts","entries":["./core"],"package":"@reformer/mcp"},{"name":"Knowledge","kind":"interface","signature":"export interface Knowledge {\\n /** Слитый индекс всех пакетов, у которых он есть. */\\n readonly index: MergedIndex;\\n /** Документация: `llms.txt` и его секции. */\\n readonly docs: DocsCorpus;\\n /** Файлы `docs/llms`; в средах без них — {@link EMPTY_RECIPE_SOURCE}. */\\n readonly recipes: RecipeSource;\\n /** Спеки; в средах без них — {@link EMPTY_SPEC_SOURCE}. */\\n readonly spec: SpecSource;\\n /** Сток отчётов; в средах без записи — {@link UNAVAILABLE_ISSUE_SINK}. */\\n readonly issues: IssueSink;\\n /** См. {@link SymbolsFallback}. */\\n readonly symbolsFallback?: SymbolsFallback;\\n /**\\n * Ленивые производные, общие на экземпляр: разобранные символы фолбэка, поисковые корпуса.\\n *\\n * Именно на экземпляр, а не на модуль. Модульный кэш был бы общим для двух разных Knowledge\\n * (например, вшитого артефакта и папки проекта), и второй молча отвечал бы данными первого.\\n */\\n readonly memo: Map<string, unknown>;\\n}","summary":"","params":[],"examplesCount":0,"sourcePath":"src/core/knowledge.ts","entries":["./core"],"package":"@reformer/mcp"},{"name":"KnowledgeSources","kind":"interface","signature":"export interface KnowledgeSources {\\n docs: DocsSource;\\n index: IndexSource;\\n /**\\n * Исходные файлы `docs/llms`. Отсутствует — первая стадия `find_recipe` (подбор по имени\\n * файла) отключается, топик уходит в каскад по секциям `llms.txt`.\\n */\\n recipes?: RecipeSource;\\n /** Текст постановки задачи. Отсутствует — `plan_form` работает только от `description`. */\\n spec?: SpecSource;\\n /** Куда сохранять отчёты `report_issue`. Отсутствует — инструмент честно откажет. */\\n issues?: IssueSink;\\n /** Отсутствует — пакеты без индекса просто не дадут символов. */\\n symbolsFallback?: SymbolsFallback;\\n}","summary":"Что платформа обязана предоставить ядру.","description":"Что платформа обязана предоставить ядру.","params":[],"examplesCount":0,"sourcePath":"src/core/knowledge.ts","entries":["./core"],"package":"@reformer/mcp"},{"name":"memoize","kind":"function","signature":"export function memoize<T>(k: Knowledge, key: string, build: () => T): T","summary":"Ленивая производная от знания, посчитанная один раз на экземпляр.","description":"Ленивая производная от знания, посчитанная один раз на экземпляр.","params":[],"examplesCount":0,"sourcePath":"src/core/knowledge.ts","entries":["./core"],"package":"@reformer/mcp"},{"name":"SymbolsFallback","kind":"type","signature":"export type SymbolsFallback = (pkg: string) => Promise<PublicSymbol[]>;","summary":"Разбор публичных символов пакета в обход индекса.","description":"Разбор публичных символов пакета в обход индекса.\\n\\nСуществует ради одного случая: рядом с сервером стоит СТАРЫЙ `@reformer/*` без\\n`llms-index.json`. В CLI это разбор TypeScript-AST, который подтягивается динамически (и\\nпотому `typescript` остаётся опциональным peer\'ом). В браузере фолбэка нет вовсе —\\nи это правильно: тащить туда компилятор ради редкого случая дороже, чем честно показать,\\nчто символы такого пакета не перечислены.","params":[],"examplesCount":0,"sourcePath":"src/core/knowledge.ts","entries":["./core"],"package":"@reformer/mcp"}]}}'),o={schemaVersion:1,builtAt:e,packages:n};export{e as builtAt,o as default,n as packages,r as schemaVersion};