@ryuzaki13/react-foundation-ui 1.8.11 → 1.8.12

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 (281) hide show
  1. package/dist/chunks/defaultRenderers-u_Vep6Pj.js.map +1 -1
  2. package/dist/chunks/multi-select-DtmRtX6v.js.map +1 -1
  3. package/dist/chunks/select-MN6zDPKM.js.map +1 -1
  4. package/dist/chunks/useODataSelectBase-DR4PrY1j.js.map +1 -1
  5. package/dist/multi-select/model/useODataMultiSelect.d.ts +1 -1
  6. package/dist/multi-select/model/useODataMultiSelect.d.ts.map +1 -1
  7. package/dist/multi-select/ui/MultiSelect.d.ts +1 -1
  8. package/dist/multi-select/ui/MultiSelect.d.ts.map +1 -1
  9. package/dist/multi-select/ui/SerializableMultiSelect.d.ts.map +1 -1
  10. package/dist/multi-select/ui/defaultRenderers.d.ts +1 -1
  11. package/dist/multi-select/ui/defaultRenderers.d.ts.map +1 -1
  12. package/dist/select/model/useODataSelect.d.ts +1 -1
  13. package/dist/select/model/useODataSelect.d.ts.map +1 -1
  14. package/dist/select/model/useODataSelectBase.d.ts +1 -1
  15. package/dist/select/model/useODataSelectBase.d.ts.map +1 -1
  16. package/dist/tree-select/index.js.map +1 -1
  17. package/dist/tree-select/model/buildODataTreeNodes.d.ts +1 -1
  18. package/dist/tree-select/model/buildODataTreeNodes.d.ts.map +1 -1
  19. package/package.json +3 -3
  20. package/storybook-static/assets/{Badge-BojMuOws.js → Badge-CveIo2LZ.js} +1 -1
  21. package/storybook-static/assets/{Badge.stories-C9gJRuIO.js → Badge.stories-Bd8M64xJ.js} +1 -1
  22. package/storybook-static/assets/{BadgeList-dNEWI7-O.js → BadgeList-xT41a0VL.js} +1 -1
  23. package/storybook-static/assets/{Button-Bbt3JzIY.js → Button-C5bBSb3k.js} +1 -1
  24. package/storybook-static/assets/{Button-CrTHXWYk.js → Button-DkDgfpHL.js} +1 -1
  25. package/storybook-static/assets/{Button.stories-BaYXOBeF.js → Button.stories-CeKPeGK5.js} +1 -1
  26. package/storybook-static/assets/{CalendarView-Dp0zus1o.js → CalendarView-CEqcrblx.js} +1 -1
  27. package/storybook-static/assets/{CheckBox-BiK9yWNt.js → CheckBox-DKeFkdOt.js} +1 -1
  28. package/storybook-static/assets/{CheckBox-UzYHaD6S.js → CheckBox-OVvAarW-.js} +1 -1
  29. package/storybook-static/assets/{CheckBox.stories-C2BOiWZj.js → CheckBox.stories-CfZ0p1yo.js} +1 -1
  30. package/storybook-static/assets/{Color-6AOWCN3U-C5S4wUlD.js → Color-6AOWCN3U-BWW7zrfs.js} +1 -1
  31. package/storybook-static/assets/{ContextMenu-BWQln_tb.js → ContextMenu-kia7is1N.js} +1 -1
  32. package/storybook-static/assets/{ContextMenu-D9EZxb7d.js → ContextMenu-xn2GtiLR.js} +1 -1
  33. package/storybook-static/assets/{ContextMenu.stories-U38zPh9_.js → ContextMenu.stories-CYuy9uXF.js} +1 -1
  34. package/storybook-static/assets/{CustomOptionButton-COIOrxQn.js → CustomOptionButton-C4w-APws.js} +1 -1
  35. package/storybook-static/assets/DateInput-BiUFIihm.js +1 -0
  36. package/storybook-static/assets/{DateInput-C-entb-r.js → DateInput-DAzE5mCE.js} +1 -1
  37. package/storybook-static/assets/{DateInput.stories-NmUXQLDU.js → DateInput.stories-BcowGCRD.js} +1 -1
  38. package/storybook-static/assets/{DateRangePresetSelect-BM1L1KOo.js → DateRangePresetSelect-CQm4dNLR.js} +1 -1
  39. package/storybook-static/assets/{DateRangePresetSelect-CAJzxaq0.js → DateRangePresetSelect-RIyqNBk9.js} +1 -1
  40. package/storybook-static/assets/{DateRangePresetSelect.stories-CC47XLnD.js → DateRangePresetSelect.stories-ypGyuGfy.js} +1 -1
  41. package/storybook-static/assets/{Detail-CDluXtts.js → Detail-CEypL2Nh.js} +1 -1
  42. package/storybook-static/assets/{Detail.stories-DjniLC4n.js → Detail.stories-DNkT7B-u.js} +1 -1
  43. package/storybook-static/assets/{Dialog-bzRSgGU7.js → Dialog-BVFFQJDH.js} +1 -1
  44. package/storybook-static/assets/{Dialog-bw6cHUsz.js → Dialog-DD0grLG3.js} +1 -1
  45. package/storybook-static/assets/{Dialog.stories-C6Rs6s_p.js → Dialog.stories-DSCypHqR.js} +1 -1
  46. package/storybook-static/assets/{Disclosure-DelA6FsQ.js → Disclosure-DauUgrev.js} +1 -1
  47. package/storybook-static/assets/{Disclosure.stories-D7yUinyb.js → Disclosure.stories-B1qB8vQZ.js} +1 -1
  48. package/storybook-static/assets/{DisclosureGroup-DbK7mU_Q.js → DisclosureGroup-D9oCCeHf.js} +1 -1
  49. package/storybook-static/assets/{DocsRenderer-JROSPFPF-v3z0zVN1.js → DocsRenderer-JROSPFPF-CmSf6tXp.js} +1 -1
  50. package/storybook-static/assets/{DropZone-Cyy-ttEO.js → DropZone-D42ueN1w.js} +1 -1
  51. package/storybook-static/assets/{DropZone-CI3NW4AC.js → DropZone-D8hbPCAv.js} +1 -1
  52. package/storybook-static/assets/{DropZone.stories-S0HSpGTB.js → DropZone.stories-DO-T_Bh4.js} +1 -1
  53. package/storybook-static/assets/{DropdownMenu-Ct1bSZsE.js → DropdownMenu-CknJDoji.js} +1 -1
  54. package/storybook-static/assets/{ExpandableActionPanel-Oj3xlasj.js → ExpandableActionPanel-Dqi_bo3c.js} +1 -1
  55. package/storybook-static/assets/{ExpandableActionPanel.stories-Ch7CLkpR.js → ExpandableActionPanel.stories-BD9QZGZN.js} +1 -1
  56. package/storybook-static/assets/{Flex-UiFm8Tkc.js → Flex-CaVn1IOP.js} +1 -1
  57. package/storybook-static/assets/{Flex.stories-CaDiVlBD.js → Flex.stories-Bp9Y6q6b.js} +1 -1
  58. package/storybook-static/assets/{FloatingPopover-CTYV9W7T.js → FloatingPopover-U7tx-Jlw.js} +1 -1
  59. package/storybook-static/assets/{FormattedTableCell-D-ysSR3p.js → FormattedTableCell-pmmhsAbN.js} +1 -1
  60. package/storybook-static/assets/{Grid-CigBXPe2.js → Grid-CEpMNurH.js} +1 -1
  61. package/storybook-static/assets/{Grid.stories-ay3z9DQZ.js → Grid.stories-BM-gO5DN.js} +1 -1
  62. package/storybook-static/assets/{ImageCropper.stories-Dkce_ugb.js → ImageCropper.stories-BWz5XU6U.js} +1 -1
  63. package/storybook-static/assets/{ImageRenderer-C9_EmGBW.js → ImageRenderer-BTYZEX5t.js} +1 -1
  64. package/storybook-static/assets/{ImageRenderer.stories-C7bXaNBI.js → ImageRenderer.stories-Dz2STM95.js} +1 -1
  65. package/storybook-static/assets/{ImageView.stories-D-ZzGlk8.js → ImageView.stories-DBVe0an3.js} +1 -1
  66. package/storybook-static/assets/{ImageViewer.stories-ItcRfxyy.js → ImageViewer.stories-C4Px97lD.js} +2 -2
  67. package/storybook-static/assets/{ImageViewerRuntime-eaupID36.js → ImageViewerRuntime-TJtlJVfa.js} +1 -1
  68. package/storybook-static/assets/{Input-op4j7Beh.js → Input-CIPgijvW.js} +1 -1
  69. package/storybook-static/assets/{Input-BUDNR96c.js → Input-D8io9jVS.js} +1 -1
  70. package/storybook-static/assets/{Input.stories-DwulvJIg.js → Input.stories-SUk3aYaC.js} +1 -1
  71. package/storybook-static/assets/{InputDateTime-B_cxOp6k.js → InputDateTime-DA5pIDuE.js} +1 -1
  72. package/storybook-static/assets/{InputDateTime.stories-BueLF4HC.js → InputDateTime.stories-DeudzDSU.js} +1 -1
  73. package/storybook-static/assets/{InputFile-C8z6TPc1.js → InputFile-C5mp5Y5I.js} +1 -1
  74. package/storybook-static/assets/{InputFile-DSg7sugm.js → InputFile-CGAC7ruP.js} +1 -1
  75. package/storybook-static/assets/{InputFile.stories-C6XSbIua.js → InputFile.stories-Cx1xQ6PE.js} +1 -1
  76. package/storybook-static/assets/{InputFiles-DoatLq3q.js → InputFiles-B7OBcPJN.js} +1 -1
  77. package/storybook-static/assets/{InputFiles-DeZ84Uu_.js → InputFiles-Hzl89Ghf.js} +1 -1
  78. package/storybook-static/assets/{InputFiles.stories-BMbE8SJU.js → InputFiles.stories-CG6QjDZH.js} +1 -1
  79. package/storybook-static/assets/{InputFilesList-CsfDDqaJ.js → InputFilesList-B6htWHF1.js} +1 -1
  80. package/storybook-static/assets/{InputImage-yJSq98EH.js → InputImage-BTa4S4Wp.js} +1 -1
  81. package/storybook-static/assets/{InputImage-D_YnB2Tw.js → InputImage-CQnoblAE.js} +1 -1
  82. package/storybook-static/assets/{InputImage.stories-nivUG307.js → InputImage.stories-CEI44Eyz.js} +1 -1
  83. package/storybook-static/assets/{InteractiveComponents-IPkC_Rkg.js → InteractiveComponents-B0ypWz1x.js} +1 -1
  84. package/storybook-static/assets/{InteractiveComponents.stories-D4VzVKZJ.js → InteractiveComponents.stories-BadApta9.js} +1 -1
  85. package/storybook-static/assets/{LayoutPicker-aMzPN5Do.js → LayoutPicker-COB9GlV_.js} +1 -1
  86. package/storybook-static/assets/{LayoutPicker-ZHkMi-LM.js → LayoutPicker-C_Uz7Tnj.js} +1 -1
  87. package/storybook-static/assets/{LayoutPicker.stories-DAzpzxn5.js → LayoutPicker.stories-Btp0IcaL.js} +1 -1
  88. package/storybook-static/assets/{Listbox-CR5nXC9J.js → Listbox-AAaZGSAl.js} +1 -1
  89. package/storybook-static/assets/{Listbox-BmfQOnrb.js → Listbox-CyfuZw7w.js} +1 -1
  90. package/storybook-static/assets/{Listbox.stories-CeOpsKxB.js → Listbox.stories-NDKQmjyQ.js} +1 -1
  91. package/storybook-static/assets/{Modal-BStp52Zo.js → Modal-BJDnJ4zv.js} +1 -1
  92. package/storybook-static/assets/{Modal.stories-CwGm5GYE.js → Modal.stories-D_X5lTLO.js} +1 -1
  93. package/storybook-static/assets/{ModalManagerProvider-B5uUXWF9.js → ModalManagerProvider-ShDjozpW.js} +1 -1
  94. package/storybook-static/assets/{MultiSelect-BDs02MZh.js → MultiSelect-B5CElQ3-.js} +1 -1
  95. package/storybook-static/assets/{MultiSelect-308npb27.js → MultiSelect-DqXfrjcH.js} +1 -1
  96. package/storybook-static/assets/{MultiSelect.stories-DRi_iTp4.js → MultiSelect.stories-fB3mcFmx.js} +1 -1
  97. package/storybook-static/assets/{NoData-ovaQEE9W.js → NoData-DDb0G7T8.js} +1 -1
  98. package/storybook-static/assets/{NotificationsHost-BpeMWhLY.js → NotificationsHost-CIGL-pKX.js} +1 -1
  99. package/storybook-static/assets/NotificationsHost.stories-B_MRb3fs.js +29 -0
  100. package/storybook-static/assets/{ODataMultiSelect-qlft9L9L.js → ODataMultiSelect-DQAitH4N.js} +1 -1
  101. package/storybook-static/assets/{ODataMultiSelect.stories-CMPIoPiy.js → ODataMultiSelect.stories-DwW221S9.js} +2 -2
  102. package/storybook-static/assets/{ODataSelect-DKBQArAK.js → ODataSelect-tiZhOIhE.js} +1 -1
  103. package/storybook-static/assets/{ODataSelect.stories-DxYIhtwe.js → ODataSelect.stories-BhaatPjK.js} +2 -2
  104. package/storybook-static/assets/{ODataTreeMultiSelect-DAt6THP3.js → ODataTreeMultiSelect-B9WqJ-Un.js} +1 -1
  105. package/storybook-static/assets/{ODataTreeMultiSelect.stories-CBNJP0mP.js → ODataTreeMultiSelect.stories-CAfKuhfU.js} +1 -1
  106. package/storybook-static/assets/{ODataTreeSelect-Bzzt4CQC.js → ODataTreeSelect-Cel1phxZ.js} +1 -1
  107. package/storybook-static/assets/{ODataTreeSelect.stories-CWVvuqOt.js → ODataTreeSelect.stories-BpBCpBA9.js} +1 -1
  108. package/storybook-static/assets/{OneStepScroller-BY5lz8qi.js → OneStepScroller-BSeGbz02.js} +1 -1
  109. package/storybook-static/assets/{Option-Rw8xwrPg.js → Option-BBtQ3GdK.js} +1 -1
  110. package/storybook-static/assets/{OptionButton-Br48w_Zg.js → OptionButton-B9nZuqqW.js} +1 -1
  111. package/storybook-static/assets/{PeriodSelect-DxSRwKw-.js → PeriodSelect-BGvhR3to.js} +1 -1
  112. package/storybook-static/assets/{PeriodSelect-8-wpXz6w.js → PeriodSelect-DA_zjcdA.js} +1 -1
  113. package/storybook-static/assets/{PeriodSelect.stories-B-qgUzlS.js → PeriodSelect.stories-DDP1eXyM.js} +1 -1
  114. package/storybook-static/assets/{PickerTriggerActions-C5xmysFh.js → PickerTriggerActions-BgvzqRBd.js} +1 -1
  115. package/storybook-static/assets/{Popover-Ds8PUigp.js → Popover-BQql18MF.js} +1 -1
  116. package/storybook-static/assets/{Popover-NJwt_vZZ.js → Popover-C0NebUMz.js} +1 -1
  117. package/storybook-static/assets/{Popover.stories-CUOFA_Xf.js → Popover.stories-CIyDUtlz.js} +1 -1
  118. package/storybook-static/assets/{PresetRangeDateInput-DyOpbkON.js → PresetRangeDateInput-BsgzPwCV.js} +1 -1
  119. package/storybook-static/assets/{PresetRangeDateInput-Xk0bOy3S.js → PresetRangeDateInput-htbxc3ni.js} +1 -1
  120. package/storybook-static/assets/{PresetRangeDateInput.stories-CwjUlXj0.js → PresetRangeDateInput.stories-ClHM5Kah.js} +1 -1
  121. package/storybook-static/assets/{PresetSelect-Ddmr0niY.js → PresetSelect-Dcx0BOTx.js} +1 -1
  122. package/storybook-static/assets/README--LCKbep-.js +110 -0
  123. package/storybook-static/assets/{README-DRnlD7y8.js → README-5M8ajrJp.js} +1 -1
  124. package/storybook-static/assets/README-5NhzH8VL.js +95 -0
  125. package/storybook-static/assets/README-Am6Fa6-b.js +69 -0
  126. package/storybook-static/assets/README-B3bFglqG.js +82 -0
  127. package/storybook-static/assets/README-B45Cwj2a.js +95 -0
  128. package/storybook-static/assets/README-B6Nq7NCU.js +416 -0
  129. package/storybook-static/assets/{README-B4zYJg6u.js → README-B6ltJiw3.js} +1 -1
  130. package/storybook-static/assets/{README-BdPlV5nA.js → README-BB_JPejH.js} +1 -1
  131. package/storybook-static/assets/README-BIq-FXcN.js +2124 -0
  132. package/storybook-static/assets/README-BSh5XUR9.js +110 -0
  133. package/storybook-static/assets/README-BXJneZAJ.js +147 -0
  134. package/storybook-static/assets/README-BYSgTTZt.js +296 -0
  135. package/storybook-static/assets/{README-BzVni2ve.js → README-BmhhWWEk.js} +1 -1
  136. package/storybook-static/assets/README-Bqnqu1bC.js +118 -0
  137. package/storybook-static/assets/README-BuMMG4_N.js +192 -0
  138. package/storybook-static/assets/README-BxjYCoYA.js +186 -0
  139. package/storybook-static/assets/{README-MzcO5Z_P.js → README-ByALXSEH.js} +1 -1
  140. package/storybook-static/assets/README-Byo6DxIF.js +101 -0
  141. package/storybook-static/assets/README-C3UcjOGB.js +208 -0
  142. package/storybook-static/assets/README-C6BOdXNV.js +322 -0
  143. package/storybook-static/assets/README-C8E1O7DQ.js +230 -0
  144. package/storybook-static/assets/README-C9eh0JLs.js +64 -0
  145. package/storybook-static/assets/README-CAGQnLsv.js +90 -0
  146. package/storybook-static/assets/README-CC00hlZK.js +527 -0
  147. package/storybook-static/assets/README-CH_6ZIO2.js +64 -0
  148. package/storybook-static/assets/README-CHbo4O3Z.js +75 -0
  149. package/storybook-static/assets/{README-CTIBG4zH.js → README-CIGfHKKE.js} +1 -1
  150. package/storybook-static/assets/{README-BHw6MVjD.js → README-CM-7E-Jf.js} +1 -1
  151. package/storybook-static/assets/{README-C0BwTe5N.js → README-CNHemCS2.js} +1 -1
  152. package/storybook-static/assets/{README-DzTc6XmY.js → README-CWfPiPIB.js} +1 -1
  153. package/storybook-static/assets/{README-Dx3cpFMr.js → README-CeK4kfFO.js} +1 -1
  154. package/storybook-static/assets/README-Cj2e6HrF.js +178 -0
  155. package/storybook-static/assets/README-CsoHGRve.js +1844 -0
  156. package/storybook-static/assets/README-D9OypaFB.js +208 -0
  157. package/storybook-static/assets/{README-CkWglKbS.js → README-DDBqoI-T.js} +1 -1
  158. package/storybook-static/assets/README-DE2wk9-v.js +1282 -0
  159. package/storybook-static/assets/README-DEj2wSK0.js +264 -0
  160. package/storybook-static/assets/{README-D-XjRtAE.js → README-DIbfpC-2.js} +1 -1
  161. package/storybook-static/assets/{README-Dki94Nf2.js → README-DJHVgrpj.js} +1 -1
  162. package/storybook-static/assets/README-DN9HKtp_.js +124 -0
  163. package/storybook-static/assets/README-DNricOkt.js +136 -0
  164. package/storybook-static/assets/README-DV4fCpqN.js +1146 -0
  165. package/storybook-static/assets/{README-BzVHwvgo.js → README-DjCArsA5.js} +1 -1
  166. package/storybook-static/assets/README-Dl92E69Z.js +1704 -0
  167. package/storybook-static/assets/README-DnA-4W65.js +226 -0
  168. package/storybook-static/assets/README-DoCA4JXf.js +273 -0
  169. package/storybook-static/assets/{README-DqQDgJN-.js → README-DvAlDsh9.js} +1 -1
  170. package/storybook-static/assets/README-Ss-3t1nX.js +158 -0
  171. package/storybook-static/assets/README-eHCINzP3.js +154 -0
  172. package/storybook-static/assets/README-qHKxXU95.js +98 -0
  173. package/storybook-static/assets/README-tm9QH9cF.js +103 -0
  174. package/storybook-static/assets/README-ui-uanyg.js +672 -0
  175. package/storybook-static/assets/{RadioButton-oSvQ-gQh.js → RadioButton-CWtjclwT.js} +1 -1
  176. package/storybook-static/assets/{RadioButton-DWbkCY8u.js → RadioButton-YIQXt0wx.js} +1 -1
  177. package/storybook-static/assets/{RadioButton.stories-GNQ9XJZT.js → RadioButton.stories-Ah-CBpeC.js} +1 -1
  178. package/storybook-static/assets/{RadioGroup-CvXjGXcV.js → RadioGroup-BnO-GL7A.js} +1 -1
  179. package/storybook-static/assets/{RadioGroup-eBYggurL.js → RadioGroup-CUS0etBD.js} +1 -1
  180. package/storybook-static/assets/{RadioGroup.stories-C77j_cPv.js → RadioGroup.stories-DGwCawtU.js} +1 -1
  181. package/storybook-static/assets/{Scrollable-De6SdhI3.js → Scrollable-D85fA6pO.js} +1 -1
  182. package/storybook-static/assets/{Select-Bwc0bEpt.js → Select-CGCxJjL9.js} +1 -1
  183. package/storybook-static/assets/{Select-DQMoVjn4.js → Select-gRnfvfGh.js} +1 -1
  184. package/storybook-static/assets/{Select.stories-BSIJKJnM.js → Select.stories-CMwt4F9i.js} +1 -1
  185. package/storybook-static/assets/{SerializableSelect-B73irNFR.js → SerializableSelect-BLXfKJ38.js} +1 -1
  186. package/storybook-static/assets/{SerializableSelect.stories-Z9q6g5v2.js → SerializableSelect.stories-Bca1a9ZU.js} +1 -1
  187. package/storybook-static/assets/{SingleDateTimeInput-Dq9LcjnS.js → SingleDateTimeInput-CyeQN0Rd.js} +1 -1
  188. package/storybook-static/assets/{SingleDateTimeInput-BHl6srqA.js → SingleDateTimeInput-xrmZckzw.js} +1 -1
  189. package/storybook-static/assets/SingleDateTimeInput.stories-BYFTQM9z.js +48 -0
  190. package/storybook-static/assets/{Slider-BiyKexKa.js → Slider-1yJ3uVeR.js} +1 -1
  191. package/storybook-static/assets/{Slider-CvM0N_kc.js → Slider-D8GtXVGI.js} +1 -1
  192. package/storybook-static/assets/{Slider.stories-CdHAMDmY.js → Slider.stories-CyQ3ns_C.js} +1 -1
  193. package/storybook-static/assets/{SliderInput-Bx_oHUCV.js → SliderInput-BOzHhEUA.js} +1 -1
  194. package/storybook-static/assets/{SliderInput-DqHotbhB.js → SliderInput-ISSx9vH_.js} +1 -1
  195. package/storybook-static/assets/{SliderInput.stories-R5yDhghM.js → SliderInput.stories-7ooTghrS.js} +1 -1
  196. package/storybook-static/assets/{Sortable-D7pjTHO0.js → Sortable-CCLiMmfZ.js} +1 -1
  197. package/storybook-static/assets/{Sortable.stories-CVLG6pSH.js → Sortable.stories-B36szI6t.js} +1 -1
  198. package/storybook-static/assets/{Splitter-B1Du6XI2.js → Splitter-DQGhgRwx.js} +1 -1
  199. package/storybook-static/assets/{Splitter.stories-D-FRLMCc.js → Splitter.stories-Hsq1wYaq.js} +1 -1
  200. package/storybook-static/assets/{StateSelect-zl-yZibY.js → StateSelect-C6hldFgO.js} +1 -1
  201. package/storybook-static/assets/{StateSelect-BJdUEUBc.js → StateSelect-DieNn4VC.js} +1 -1
  202. package/storybook-static/assets/{StateSelect.stories-DgidR5zR.js → StateSelect.stories-CvAhDMix.js} +1 -1
  203. package/storybook-static/assets/{StringToggle.stories-IucGrtIi.js → StringToggle.stories-CUT1tvt-.js} +1 -1
  204. package/storybook-static/assets/{Switch-BJrn2lIN.js → Switch-CX9p_uYU.js} +1 -1
  205. package/storybook-static/assets/{Switch-5dCshvVo.js → Switch-nEMRtcWe.js} +1 -1
  206. package/storybook-static/assets/{Switch.stories-Dp_l3_JL.js → Switch.stories-CPsHa2_m.js} +1 -1
  207. package/storybook-static/assets/{Table-BFAEcUde.js → Table-BhtITVtj.js} +1 -1
  208. package/storybook-static/assets/{Table.stories-CohejRQv.js → Table.stories-nWNhSydG.js} +2 -2
  209. package/storybook-static/assets/{Tabs-CI32QiHf.js → Tabs-DMQFh2BJ.js} +1 -1
  210. package/storybook-static/assets/{Tabs.stories-Cr9d9ipA.js → Tabs.stories-D23_xvom.js} +1 -1
  211. package/storybook-static/assets/{TabsBox-BlDOUDMF.js → TabsBox-B5BsD_j_.js} +1 -1
  212. package/storybook-static/assets/{TagInput-YZ7eSv8W.js → TagInput-DO17z100.js} +1 -1
  213. package/storybook-static/assets/{TagInput.stories-DrOvsiI5.js → TagInput.stories-CMMFnIzb.js} +1 -1
  214. package/storybook-static/assets/{Text-DK4jN26J.js → Text-ClnbDqRk.js} +1 -1
  215. package/storybook-static/assets/{Textarea-DxPuWBZj.js → Textarea-C2IO_zsP.js} +1 -1
  216. package/storybook-static/assets/{Textarea-CFh5f_lC.js → Textarea-DkhohiNc.js} +1 -1
  217. package/storybook-static/assets/{Textarea.stories-CUeOGKYc.js → Textarea.stories-NL6Aq8Vc.js} +1 -1
  218. package/storybook-static/assets/{TimePanel-BUhFtwlb.js → TimePanel-DNEPDlSW.js} +1 -1
  219. package/storybook-static/assets/{TimePanel.stories-CpXpMBDN.js → TimePanel.stories-DlfdPsz1.js} +1 -1
  220. package/storybook-static/assets/{Toggle-BtApzBNH.js → Toggle-3U5CceQN.js} +1 -1
  221. package/storybook-static/assets/{Toggle-l2AvDbRn.js → Toggle-Cc6Ca-HI.js} +1 -1
  222. package/storybook-static/assets/{Toggle.stories-Ca8otmAa.js → Toggle.stories-BR-hVLDp.js} +1 -1
  223. package/storybook-static/assets/{TreeMultiSelect-nXC4ZB5b.js → TreeMultiSelect-B0oBc-4y.js} +1 -1
  224. package/storybook-static/assets/{TreeMultiSelect-C9QDV63L.js → TreeMultiSelect-D9hMQN2O.js} +1 -1
  225. package/storybook-static/assets/{TreeMultiSelect.stories-6STRGJbF.js → TreeMultiSelect.stories-CslpbvPR.js} +1 -1
  226. package/storybook-static/assets/{TreePickerBase-Cq7fSw3x.js → TreePickerBase-B_dMCe45.js} +1 -1
  227. package/storybook-static/assets/{TreeSelect-CITef9rp.js → TreeSelect-2lj0Q8gm.js} +1 -1
  228. package/storybook-static/assets/{TreeSelect-rMNyu_KT.js → TreeSelect-DEKNYF2b.js} +1 -1
  229. package/storybook-static/assets/{TreeSelect.stories-B-Emz9yW.js → TreeSelect.stories-CVDxn8Vm.js} +1 -1
  230. package/storybook-static/assets/{TreeTable-CLiP0td3.js → TreeTable-CBIpzYRL.js} +1 -1
  231. package/storybook-static/assets/{TreeTable.stories-DJb9qt8k.js → TreeTable.stories-BMzrr2Kc.js} +2 -2
  232. package/storybook-static/assets/{blocks-DndFRxxW.js → blocks-B5YBxaaS.js} +3 -3
  233. package/storybook-static/assets/{check-CLkTJVXe.js → check-BjtdCRaW.js} +1 -1
  234. package/storybook-static/assets/{chevron-down-miCejSEn.js → chevron-down-B4u-y8Z1.js} +1 -1
  235. package/storybook-static/assets/{chevron-left-DhQIPej2.js → chevron-left-BQfWs7Ah.js} +1 -1
  236. package/storybook-static/assets/{chevron-right-DfBBx-fr.js → chevron-right-ChokKd-f.js} +1 -1
  237. package/storybook-static/assets/{chunk-W22LQPXL-IdwKKJUw.js → chunk-W22LQPXL-meOkhzk4.js} +1 -1
  238. package/storybook-static/assets/{circle-alert-DOmVf8am.js → circle-alert-B1AnDRf_.js} +1 -1
  239. package/storybook-static/assets/{circle-check-e7eSQ2VD.js → circle-check-JYnlcC1F.js} +1 -1
  240. package/storybook-static/assets/{components-Bm4Cw8Ap.js → components-C_wl1sL5.js} +3 -3
  241. package/storybook-static/assets/{contextMenu-DpIKeJju.js → contextMenu-B-TUGs_1.js} +1 -1
  242. package/storybook-static/assets/{defaultRenderers-m21aWJXz.js → defaultRenderers-DfmnIuod.js} +1 -1
  243. package/storybook-static/assets/{download-eAKjms6q.js → download-eR3X8I-h.js} +1 -1
  244. package/storybook-static/assets/{floating-ui.react-DmilONq6.js → floating-ui.react-D95VPQ0b.js} +1 -1
  245. package/storybook-static/assets/formatters-D33Uh3si-CxrG0jsB.js +1 -0
  246. package/storybook-static/assets/foundationApi-QhHXpYLB.js +59 -0
  247. package/storybook-static/assets/foundationLib-CEAjnstw.js +30 -0
  248. package/storybook-static/assets/{hooks-RI5_2AXI.js → hooks-awde7r2r.js} +1 -1
  249. package/storybook-static/assets/iframe-DzQq_POR.js +1 -0
  250. package/storybook-static/assets/{iframe-Sr0umHM6.js → iframe-FSp_AjJa.js} +4 -4
  251. package/storybook-static/assets/{info-DhJTzwcL.js → info-12vmb1sT.js} +1 -1
  252. package/storybook-static/assets/odata-C0Kpvttz.js +1 -0
  253. package/storybook-static/assets/odata-service-CWkHASdw-DlmSiioz.js +3 -0
  254. package/storybook-static/assets/{odataStoryFixtures-lgnWIUp7.js → odataStoryFixtures-BXZnk_C7.js} +1 -1
  255. package/storybook-static/assets/{react-YFbUKK0m.js → react-BlCqWuXr.js} +1 -1
  256. package/storybook-static/assets/{refresh-cw-C7WnxX9M.js → refresh-cw-Bf5ufPte.js} +1 -1
  257. package/storybook-static/assets/{settings-2-0NVvyKQl.js → settings-2-DR-dTXIC.js} +1 -1
  258. package/storybook-static/assets/{sortable-DDGG-Zfs.js → sortable-B5e5yb_-.js} +1 -1
  259. package/storybook-static/assets/{syntaxhighlighter-QEQV7K2Y-CxWm8nc8.js → syntaxhighlighter-QEQV7K2Y-EVJARTec.js} +1 -1
  260. package/storybook-static/assets/{trash-2-BnceCuhg.js → trash-2-QP7TS18H.js} +1 -1
  261. package/storybook-static/assets/{triangle-alert-MPi3GVgt.js → triangle-alert-qw19mxHr.js} +1 -1
  262. package/storybook-static/assets/{useODataSelectBase-hmjK6chS.js → useODataSelectBase-Csu_Cct9.js} +1 -1
  263. package/storybook-static/assets/useODataTreeData-BAv-Twqf.js +1 -0
  264. package/storybook-static/assets/{usePickerQuery-CtsGhieD.js → usePickerQuery-Da-XM_Y0.js} +1 -1
  265. package/storybook-static/assets/{usePickerTriggerController-EaI8W2G0.js → usePickerTriggerController-C0TdC2Pz.js} +1 -1
  266. package/storybook-static/assets/{x-CqPSvWfo.js → x-aCjYTirW.js} +1 -1
  267. package/storybook-static/iframe.html +2 -2
  268. package/storybook-static/index.json +1 -1
  269. package/storybook-static/project.json +1 -1
  270. package/storybook-static/assets/DateInput-05Iy69_a.js +0 -1
  271. package/storybook-static/assets/NotificationsHost.stories-CgbFboVD.js +0 -29
  272. package/storybook-static/assets/SingleDateTimeInput.stories-C2RuBRAF.js +0 -48
  273. package/storybook-static/assets/async-SjiCjIjO.js +0 -625
  274. package/storybook-static/assets/formatters-CBgrBeSA-CqB1pZxS.js +0 -1
  275. package/storybook-static/assets/foundationLib-DRrox3tN.js +0 -25
  276. package/storybook-static/assets/iframe-DQo-3eW2.js +0 -1
  277. package/storybook-static/assets/odata-DhISMZkE.js +0 -1
  278. package/storybook-static/assets/odata-service-B6TxBSLm-Bq8Ya67E.js +0 -3
  279. package/storybook-static/assets/odataFetchFn-Dv6Xi5CI.js +0 -763
  280. package/storybook-static/assets/persisted-CUFiw53N.js +0 -600
  281. package/storybook-static/assets/useODataTreeData-CKuavbWc.js +0 -1
@@ -0,0 +1,1146 @@
1
+ import{n as e}from"./rolldown-runtime-DkW27tQK.js";import{n as t}from"./iframe-FSp_AjJa.js";import{i as n,r}from"./react-Bl2r1tuC.js";import{l as i,m as a}from"./blocks-B5YBxaaS.js";function o(e){let t={a:`a`,blockquote:`blockquote`,code:`code`,h1:`h1`,h2:`h2`,h3:`h3`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,table:`table`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation Lib/API/Utils`}),`
2
+ `,(0,c.jsxs)(t.h1,{id:`общие-утилиты-ryuzaki13react-foundation-libutils`,children:[`Общие утилиты `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/utils`})]}),`
3
+ `,(0,c.jsxs)(t.p,{children:[`Модуль `,(0,c.jsx)(t.code,{children:`utils`}),` объединяет небольшие технические функции, которые нужны в разных частях React- и TypeScript-приложения:`]}),`
4
+ `,(0,c.jsxs)(t.ul,{children:[`
5
+ `,(0,c.jsxs)(t.li,{children:[`сборка строки `,(0,c.jsx)(t.code,{children:`className`}),`;`]}),`
6
+ `,(0,c.jsx)(t.li,{children:`глубокое копирование данных без функций;`}),`
7
+ `,(0,c.jsx)(t.li,{children:`стабильная JSON-сериализация;`}),`
8
+ `,(0,c.jsx)(t.li,{children:`UTF-8-кодирование текста в Base64;`}),`
9
+ `,(0,c.jsx)(t.li,{children:`обработка клавиатурной активации и расчёт следующего элемента навигации;`}),`
10
+ `,(0,c.jsx)(t.li,{children:`ленивое подключение React-компонентов;`}),`
11
+ `,(0,c.jsx)(t.li,{children:`подсчёт React children;`}),`
12
+ `,(0,c.jsx)(t.li,{children:`копирование древовидной структуры;`}),`
13
+ `,(0,c.jsxs)(t.li,{children:[`единая точка вывода ошибок в `,(0,c.jsx)(t.code,{children:`console.error`}),`.`]}),`
14
+ `]}),`
15
+ `,(0,c.jsx)(t.p,{children:`Документ рассчитан на разработчика без доступа к исходному коду пакета и с минимальным знанием JavaScript, TypeScript и React. Поэтому ниже объясняются назначение каждого аргумента, точный результат, побочные эффекты, различия похожих функций и ограничения.`}),`
16
+ `,(0,c.jsxs)(t.blockquote,{children:[`
17
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`utils`}),` — это опубликованный entrypoint, а не приглашение складывать сюда любую бизнес-логику. В модуле нет HTTP-запросов, UI-компонентов, доменных правил, нормализации пользовательского ввода и криптографии.`]}),`
18
+ `]}),`
19
+ `,(0,c.jsx)(t.h2,{id:`содержание`,children:`Содержание`}),`
20
+ `,(0,c.jsxs)(t.ul,{children:[`
21
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BD%D0%B0%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%8B`,children:`Назначение и границы`})}),`
22
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B8-%D0%B8%D0%BC%D0%BF%D0%BE%D1%80%D1%82`,children:`Установка и импорт`})}),`
23
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%81%D1%80%D0%B5%D0%B4%D0%B0-%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F`,children:`Среда выполнения`})}),`
24
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BC%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%BD%D1%8F%D1%82%D0%B8%D1%8F`,children:`Минимальные понятия`})}),`
25
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BA%D0%B0%D0%BA-%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D1%82%D1%8C-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8E`,children:`Как выбрать функцию`})}),`
26
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D1%81%D1%82%D0%B0%D1%80%D1%82`,children:`Быстрый старт`})}),`
27
+ `,(0,c.jsx)(t.li,{children:(0,c.jsxs)(t.a,{href:`#cn-%D0%B8-deprecated-classnames`,children:[(0,c.jsx)(t.code,{children:`cn`}),` и deprecated `,(0,c.jsx)(t.code,{children:`classNames`})]})}),`
28
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BA%D0%B0%D0%BA-%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D1%82%D1%8C-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8E-%D0%BA%D0%BB%D0%BE%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F`,children:`Как выбрать функцию клонирования`})}),`
29
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#deepcopywithoutfunctions`,children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})})}),`
30
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#deepclonewithoutfunctions`,children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})})}),`
31
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#clone-%D0%BD%D0%B5-%D1%8F%D0%B2%D0%BB%D1%8F%D0%B5%D1%82%D1%81%D1%8F-normalize`,children:`Clone не является normalize`})}),`
32
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#stablestringify`,children:(0,c.jsx)(t.code,{children:`stableStringify`})})}),`
33
+ `,(0,c.jsx)(t.li,{children:(0,c.jsxs)(t.a,{href:`#tobase64-%D0%B8-encodebase64`,children:[(0,c.jsx)(t.code,{children:`toBase64`}),` и `,(0,c.jsx)(t.code,{children:`encodeBase64`})]})}),`
34
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BA%D0%BB%D0%B0%D0%B2%D0%B8%D0%B0%D1%82%D1%83%D1%80%D0%BD%D0%B0%D1%8F-%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%B0%D1%86%D0%B8%D1%8F`,children:`Клавиатурная активация`})}),`
35
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#roving-focus`,children:`Roving focus`})}),`
36
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BD%D0%B0%D0%B2%D0%B8%D0%B3%D0%B0%D1%86%D0%B8%D1%8F-%D0%BF%D0%BE-%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D1%8B%D0%BC-%D0%BE%D0%BF%D1%86%D0%B8%D1%8F%D0%BC`,children:`Навигация по доступным опциям`})}),`
37
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#createlazycomponent`,children:(0,c.jsx)(t.code,{children:`createLazyComponent`})})}),`
38
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#childrencount`,children:(0,c.jsx)(t.code,{children:`childrenCount`})})}),`
39
+ `,(0,c.jsx)(t.li,{children:(0,c.jsxs)(t.a,{href:`#deepcopynodes-%D0%B8-deepcopytree`,children:[(0,c.jsx)(t.code,{children:`deepCopyNodes`}),` и `,(0,c.jsx)(t.code,{children:`deepCopyTree`})]})}),`
40
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#logerror`,children:(0,c.jsx)(t.code,{children:`logError`})})}),`
41
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#ssr-browser-%D0%B8-react-%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%8B`,children:`SSR, browser и React-границы`})}),`
42
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C`,children:`Производительность`})}),`
43
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-consumer-%D0%BA%D0%BE%D0%B4%D0%B0`,children:`Тестирование consumer-кода`})}),`
44
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-api-%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%87%D0%BD%D0%B8%D0%BA`,children:`Полный API-справочник`})}),`
45
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D1%82%D0%B8%D0%BF%D0%B8%D1%87%D0%BD%D1%8B%D0%B5-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B8`,children:`Типичные ошибки`})}),`
46
+ `,(0,c.jsx)(t.li,{children:(0,c.jsx)(t.a,{href:`#%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D1%8B-%D0%B8-%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%8B`,children:`Вопросы и ответы`})}),`
47
+ `]}),`
48
+ `,(0,c.jsx)(t.h2,{id:`назначение-и-границы`,children:`Назначение и границы`}),`
49
+ `,(0,c.jsx)(t.h3,{id:`что-делает-модуль`,children:`Что делает модуль`}),`
50
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`utils`}),` предоставляет общие технические операции, не зависящие от бизнес-сущности приложения:`]}),`
51
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`входные данные или UI-событие
52
+
53
+
54
+ маленькая utility-функция
55
+
56
+
57
+ строка / копия / индекс / React lazy component
58
+ `})}),`
59
+ `,(0,c.jsxs)(t.p,{children:[`Большинство функций являются синхронными: они сразу возвращают результат. Исключение по жизненному циклу — `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),`: функция синхронно создаёт React lazy component, но его модуль загружается асинхронно только при первом рендере.`]}),`
60
+ `,(0,c.jsx)(t.h3,{id:`чего-модуль-не-делает`,children:`Чего модуль не делает`}),`
61
+ `,(0,c.jsx)(t.p,{children:`Модуль:`}),`
62
+ `,(0,c.jsxs)(t.ul,{children:[`
63
+ `,(0,c.jsx)(t.li,{children:`не отправляет HTTP- или OData-запросы;`}),`
64
+ `,(0,c.jsx)(t.li,{children:`не создаёт готовые визуальные компоненты;`}),`
65
+ `,(0,c.jsx)(t.li,{children:`не хранит React state и не создаёт store;`}),`
66
+ `,(0,c.jsx)(t.li,{children:`не валидирует backend payload;`}),`
67
+ `,(0,c.jsx)(t.li,{children:`не нормализует пользовательский draft;`}),`
68
+ `,(0,c.jsx)(t.li,{children:`не шифрует данные и не создаёт криптографические подписи;`}),`
69
+ `,(0,c.jsx)(t.li,{children:`не декодирует Base64 обратно в строку;`}),`
70
+ `,(0,c.jsx)(t.li,{children:`не управляет DOM-фокусом самостоятельно;`}),`
71
+ `,(0,c.jsx)(t.li,{children:`не заменяет Error Boundary, logger transport или error-reporting service;`}),`
72
+ `,(0,c.jsx)(t.li,{children:`не гарантирует копирование любого встроенного browser/JavaScript-объекта.`}),`
73
+ `]}),`
74
+ `,(0,c.jsx)(t.h3,{id:`соседние-владельцы`,children:`Соседние владельцы`}),`
75
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Задача`}),(0,c.jsx)(t.th,{children:`Предпочтительный модуль`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Массивы, группировка, дедупликация и reorder`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/array`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Runtime-проверки `,(0,c.jsx)(t.code,{children:`unknown`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/validators`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Hash, UUID и стабильный DOM id`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/crypto`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Base64/Binary в `,(0,c.jsx)(t.code,{children:`Blob`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/binary`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Clipboard`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/copy`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`DOM, portal, focus и browser download`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/dom`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Debounce, throttle и React hooks`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/hooks`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Форматирование дат, чисел, строк и value state`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/formatters`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Сериализуемый error report и его доставка`}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/error-report`}),` и API-пакет`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`UI primitives`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-ui/<module>`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Бизнес-преобразование сущности`}),(0,c.jsx)(t.td,{children:`entity/feature/widget host-приложения`})]})]})]}),`
76
+ `,(0,c.jsx)(t.h2,{id:`установка-и-импорт`,children:`Установка и импорт`}),`
77
+ `,(0,c.jsx)(t.p,{children:`Установите пакет:`}),`
78
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-bash`,children:`npm install @ryuzaki13/react-foundation-lib
79
+ `})}),`
80
+ `,(0,c.jsxs)(t.p,{children:[`Entrypoint `,(0,c.jsx)(t.code,{children:`/utils`}),` также экспортирует React-функции `,(0,c.jsx)(t.code,{children:`childrenCount`}),` и `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),`. Поэтому host-приложение должно разрешить совместимую peer dependency React:`]}),`
81
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-bash`,children:`npm install react
82
+ `})}),`
83
+ `,(0,c.jsxs)(t.p,{children:[`Текущий контракт пакета рассчитан на React `,(0,c.jsx)(t.code,{children:`>=19.2.0 <20.0.0`}),`.`]}),`
84
+ `,(0,c.jsx)(t.p,{children:`Импортируйте API только из опубликованного subpath:`}),`
85
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { cn, deepCopyWithoutFunctions, handleKeyboardActivation, stableStringify, toBase64 } from "@ryuzaki13/react-foundation-lib/utils";
86
+ `})}),`
87
+ `,(0,c.jsxs)(t.p,{children:[`Публичные типы импортируйте через `,(0,c.jsx)(t.code,{children:`import type`}),`:`]}),`
88
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import type {
89
+ KeyboardActivationKey,
90
+ PureClassName,
91
+ RovingFocusTargetOptions,
92
+ ToggleClassName
93
+ } from "@ryuzaki13/react-foundation-lib/utils";
94
+ `})}),`
95
+ `,(0,c.jsx)(t.p,{children:`Неверные варианты:`}),`
96
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`// Корневой entrypoint пакета не опубликован.
97
+ import { cn } from "@ryuzaki13/react-foundation-lib";
98
+
99
+ // Внутренний файл не является публичным контрактом.
100
+ import { cn } from "@ryuzaki13/react-foundation-lib/dist/utils/cn";
101
+
102
+ // Исходный путь пакета также нельзя использовать из consumer-приложения.
103
+ import { cn } from "@ryuzaki13/react-foundation-lib/src/utils/cn";
104
+ `})}),`
105
+ `,(0,c.jsxs)(t.p,{children:[`Пакет распространяется как ESM. Используйте `,(0,c.jsx)(t.code,{children:`import`}),`, а не CommonJS `,(0,c.jsx)(t.code,{children:`require`}),`.`]}),`
106
+ `,(0,c.jsx)(t.h3,{id:`почему-некоторые-типы-опций-нельзя-импортировать`,children:`Почему некоторые типы опций нельзя импортировать`}),`
107
+ `,(0,c.jsxs)(t.p,{children:[`Типы параметров `,(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),`, `,(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`}),`, `,(0,c.jsx)(t.code,{children:`handleKeyboardActivation`}),`, `,(0,c.jsx)(t.code,{children:`findNextEnabledIndex`}),` и `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),` участвуют в публичных сигнатурах, но не экспортируются как отдельные имена. Обычно это не мешает: TypeScript проверит переданный объект прямо в месте вызова.`]}),`
108
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`deepCopyWithoutFunctions(source, {
109
+ arrayFunctionStrategy: "undefined"
110
+ });
111
+ `})}),`
112
+ `,(0,c.jsx)(t.p,{children:`Не импортируйте внутренние типы глубоким путём. Если тип нужен для собственной обёртки, получите его из публичной функции:`}),`
113
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type DeepCopyOptions = NonNullable<Parameters<typeof deepCopyWithoutFunctions>[1]>;
114
+ `})}),`
115
+ `,(0,c.jsx)(t.h2,{id:`среда-выполнения`,children:`Среда выполнения`}),`
116
+ `,(0,c.jsx)(t.p,{children:`У разных функций разные runtime-требования:`}),`
117
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`API`}),(0,c.jsx)(t.th,{style:{textAlign:`center`},children:`React`}),(0,c.jsx)(t.th,{style:{textAlign:`center`},children:`Browser API`}),(0,c.jsx)(t.th,{style:{textAlign:`center`},children:`Можно вызвать на сервере`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`cn`}),`, clone-функции, `,(0,c.jsx)(t.code,{children:`stableStringify`}),`, keyboard/select navigation, tree copy`]}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`logError`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`да, если доступен console`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`childrenCount`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`да`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`createLazyComponent`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`да`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`создаётся да; рендер по правилам React`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`toBase64`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsxs)(t.td,{style:{textAlign:`center`},children:[(0,c.jsx)(t.code,{children:`btoa`}),`, `,(0,c.jsx)(t.code,{children:`TextEncoder`})]}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`только при наличии API`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`encodeBase64`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`нет`}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:(0,c.jsx)(t.code,{children:`btoa`})}),(0,c.jsx)(t.td,{style:{textAlign:`center`},children:`только при наличии API`})]})]})]}),`
118
+ `,(0,c.jsxs)(t.p,{children:[`В современных браузерах нужные Base64 API обычно доступны. В Node.js их наличие зависит от версии и окружения. Модуль намеренно не подменяет их через `,(0,c.jsx)(t.code,{children:`Buffer`}),`.`]}),`
119
+ `,(0,c.jsx)(t.h2,{id:`минимальные-понятия`,children:`Минимальные понятия`}),`
120
+ `,(0,c.jsx)(t.h3,{id:`примитивы-и-ссылочные-значения`,children:`Примитивы и ссылочные значения`}),`
121
+ `,(0,c.jsxs)(t.p,{children:[`Строки, числа, `,(0,c.jsx)(t.code,{children:`boolean`}),`, `,(0,c.jsx)(t.code,{children:`null`}),` и `,(0,c.jsx)(t.code,{children:`undefined`}),` — примитивные значения. Объекты, массивы, `,(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`}),`, `,(0,c.jsx)(t.code,{children:`Date`}),` и функции — ссылочные значения.`]}),`
122
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const source = { name: "Анна" };
123
+ const same = source;
124
+
125
+ console.log(same === source); // true: обе переменные указывают на один объект.
126
+ `})}),`
127
+ `,(0,c.jsx)(t.p,{children:`Копия должна иметь другое внешнее значение:`}),`
128
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const copy = deepCopyWithoutFunctions(source);
129
+
130
+ console.log(copy === source); // false.
131
+ console.log(copy.name); // "Анна".
132
+ `})}),`
133
+ `,(0,c.jsx)(t.h3,{id:`поверхностная-и-глубокая-копия`,children:`Поверхностная и глубокая копия`}),`
134
+ `,(0,c.jsx)(t.p,{children:`Поверхностная копия создаёт только новый внешний объект:`}),`
135
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const source = { profile: { city: "Казань" } };
136
+ const shallow = { ...source };
137
+
138
+ console.log(shallow !== source); // true.
139
+ console.log(shallow.profile === source.profile); // true: вложенный объект общий.
140
+ `})}),`
141
+ `,(0,c.jsx)(t.p,{children:`Глубокая копия рекурсивно копирует поддерживаемые вложенные значения:`}),`
142
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const deep = deepCopyWithoutFunctions(source);
143
+
144
+ console.log(deep.profile === source.profile); // false.
145
+ `})}),`
146
+ `,(0,c.jsx)(t.h3,{id:`мутация`,children:`Мутация`}),`
147
+ `,(0,c.jsx)(t.p,{children:`Мутация — изменение уже существующего объекта:`}),`
148
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`source.profile.city = "Пермь";
149
+ `})}),`
150
+ `,(0,c.jsx)(t.p,{children:`Функции клонирования и tree copy не изменяют входное значение. Они создают новый результат. Но копирование дерева клонирует только узлы и массивы дочерних узлов, а не каждое произвольное вложенное поле.`}),`
151
+ `,(0,c.jsx)(t.h3,{id:`функция-как-значение`,children:`Функция как значение`}),`
152
+ `,(0,c.jsx)(t.p,{children:`Функцию можно хранить в поле объекта или элементе массива:`}),`
153
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const value = {
154
+ id: "A",
155
+ onClick: () => console.log("click")
156
+ };
157
+ `})}),`
158
+ `,(0,c.jsx)(t.p,{children:`Clone-функции этого модуля специально не переносят функции в результат. Это полезно для data-only конфигураций и snapshots, но не подходит для клонирования объектов, где callback является обязательной частью поведения.`}),`
159
+ `,(0,c.jsx)(t.h3,{id:`индекс-массива-и-разреженный-массив`,children:`Индекс массива и разреженный массив`}),`
160
+ `,(0,c.jsx)(t.p,{children:`Индекс — позиция элемента, начиная с нуля. Разреженный массив содержит пропущенную позицию, то есть «дыру»:`}),`
161
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const sparse = ["A", , "C"];
162
+
163
+ console.log(sparse.length); // 3.
164
+ console.log(1 in sparse); // false: индекс 1 отсутствует.
165
+ `})}),`
166
+ `,(0,c.jsxs)(t.p,{children:[`Это не то же самое, что явное значение `,(0,c.jsx)(t.code,{children:`undefined`}),`:`]}),`
167
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const indexed = ["A", undefined, "C"];
168
+
169
+ console.log(1 in indexed); // true.
170
+ `})}),`
171
+ `,(0,c.jsxs)(t.p,{children:[`Разница важна для `,(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`}),`.`]}),`
172
+ `,(0,c.jsxs)(t.h3,{id:`json-и-base64`,children:[(0,c.jsx)(t.code,{children:`JSON`}),` и Base64`]}),`
173
+ `,(0,c.jsxs)(t.p,{children:[`JSON — текстовый формат данных. `,(0,c.jsx)(t.code,{children:`stableStringify`}),` создаёт JSON-строку с отсортированными ключами объектов.`]}),`
174
+ `,(0,c.jsx)(t.p,{children:`Base64 — способ представить байты печатными символами. Это кодирование, а не шифрование: любой получатель может декодировать исходный текст.`}),`
175
+ `,(0,c.jsx)(t.h2,{id:`как-выбрать-функцию`,children:`Как выбрать функцию`}),`
176
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Задача`}),(0,c.jsx)(t.th,{children:`API`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Собрать `,(0,c.jsx)(t.code,{children:`className`}),` из строк и boolean-флагов`]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`cn`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Поддержать старый код с прежним именем`}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`classNames`}),`, но новый код — `,(0,c.jsx)(t.code,{children:`cn`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Клонировать строгую data-only конфигурацию`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Клонировать также `,(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`}),`, `,(0,c.jsx)(t.code,{children:`RegExp`}),`, cycles и descriptors`]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Получить одинаковый JSON для объектов с разным порядком ключей`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`stableStringify`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Кодировать Unicode-текст в стандартный Base64`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`toBase64`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Распознать `,(0,c.jsx)(t.code,{children:`Enter`}),` или пробел`]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isKeyboardActivationKey`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Активировать кастомный control с клавиатуры`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`handleKeyboardActivation`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Рассчитать новый индекс для `,(0,c.jsx)(t.code,{children:`Tabs`}),`/`,(0,c.jsx)(t.code,{children:`RadioGroup`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Найти первую, последнюю или следующую enabled-опцию`}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`findFirstEnabledIndex`}),`, `,(0,c.jsx)(t.code,{children:`findLastEnabledIndex`}),`, `,(0,c.jsx)(t.code,{children:`findNextEnabledIndex`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Лениво загрузить именованный React-компонент`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`createLazyComponent`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Посчитать React children, раскрывая fragments`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`childrenCount`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Скопировать узлы дерева с полем `,(0,c.jsx)(t.code,{children:`children`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyNodes`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Скопировать дерево с произвольным названием поля детей`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyTree`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`Направить ошибку в `,(0,c.jsx)(t.code,{children:`globalThis.console.error`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`logError`})})]})]})]}),`
177
+ `,(0,c.jsx)(t.h2,{id:`быстрый-старт`,children:`Быстрый старт`}),`
178
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { cn, deepCopyWithoutFunctions, findNextEnabledIndex, stableStringify, toBase64 } from "@ryuzaki13/react-foundation-lib/utils";
179
+
180
+ const className = cn("button", {
181
+ "button--active": true,
182
+ "button--disabled": false
183
+ });
184
+ // "button button--active"
185
+
186
+ const draft = {
187
+ title: "Новая группа ",
188
+ enabled: false,
189
+ items: [{ id: "A" }],
190
+ onSave: () => undefined
191
+ };
192
+
193
+ const copy = deepCopyWithoutFunctions(draft);
194
+ // title сохраняет завершающий пробел, enabled остаётся false,
195
+ // items глубоко скопирован, onSave отсутствует.
196
+
197
+ const cachePart = stableStringify({ page: 1, filter: { status: "OPEN" } });
198
+ // '{"filter":{"status":"OPEN"},"page":1}'
199
+
200
+ const encoded = toBase64("Привет");
201
+ // Стандартная Base64-строка для UTF-8-байтов текста.
202
+
203
+ const options = [{ disabled: false }, { disabled: true }, { disabled: false }];
204
+ const nextIndex = findNextEnabledIndex(options, 0, 1, (option) => option.disabled);
205
+ // 2: индекс 1 пропущен, потому что опция disabled.
206
+ `})}),`
207
+ `,(0,c.jsxs)(t.h2,{id:`cn-и-deprecated-classnames`,children:[(0,c.jsx)(t.code,{children:`cn`}),` и deprecated `,(0,c.jsx)(t.code,{children:`classNames`})]}),`
208
+ `,(0,c.jsx)(t.h3,{id:`назначение`,children:`Назначение`}),`
209
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`cn`}),` собирает одну строку CSS-классов из:`]}),`
210
+ `,(0,c.jsxs)(t.ul,{children:[`
211
+ `,(0,c.jsx)(t.li,{children:`строк;`}),`
212
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`false`}),`, `,(0,c.jsx)(t.code,{children:`undefined`}),`, `,(0,c.jsx)(t.code,{children:`null`}),`, пустой строки и `,(0,c.jsx)(t.code,{children:`true`}),`, которые игнорируются;`]}),`
213
+ `,(0,c.jsxs)(t.li,{children:[`объекта вида `,(0,c.jsx)(t.code,{children:`{ "имя-класса": условие }`}),`.`]}),`
214
+ `]}),`
215
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { cn } from "@ryuzaki13/react-foundation-lib/utils";
216
+
217
+ const result = cn("button", isPrimary && "button--primary", {
218
+ "button--loading": isLoading,
219
+ "button--disabled": disabled
220
+ });
221
+ `})}),`
222
+ `,(0,c.jsxs)(t.p,{children:[`Если `,(0,c.jsx)(t.code,{children:`isPrimary === true`}),`, `,(0,c.jsx)(t.code,{children:`isLoading === false`}),`, `,(0,c.jsx)(t.code,{children:`disabled === true`}),`, результат:`]}),`
223
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`button button--primary button--disabled
224
+ `})}),`
225
+ `,(0,c.jsx)(t.h3,{id:`сигнатура`,children:`Сигнатура`}),`
226
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type PureClassName = string | boolean | undefined | null;
227
+ type ToggleClassName = Record<string, boolean | undefined>;
228
+
229
+ function cn(...args: Array<PureClassName | ToggleClassName>): string;
230
+ `})}),`
231
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`...args`}),` означает любое количество аргументов.`]}),`
232
+ `,(0,c.jsx)(t.h3,{id:`точные-правила`,children:`Точные правила`}),`
233
+ `,(0,c.jsxs)(t.ul,{children:[`
234
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`cn()`}),` возвращает пустую строку `,(0,c.jsx)(t.code,{children:`""`}),`.`]}),`
235
+ `,(0,c.jsx)(t.li,{children:`Строки добавляются в порядке аргументов.`}),`
236
+ `,(0,c.jsx)(t.li,{children:`Ключи объекта с truthy-значением добавляются в порядке обхода объекта.`}),`
237
+ `,(0,c.jsx)(t.li,{children:`Строки не обрезаются и не разбиваются на отдельные слова.`}),`
238
+ `,(0,c.jsx)(t.li,{children:`Повторяющиеся классы не удаляются.`}),`
239
+ `,(0,c.jsx)(t.li,{children:`Числа не входят в публичный тип и в runtime игнорируются.`}),`
240
+ `,(0,c.jsxs)(t.li,{children:[`Массивы игнорируются: `,(0,c.jsx)(t.code,{children:`cn`}),` не является рекурсивным `,(0,c.jsx)(t.code,{children:`classnames`}),`-парсером.`]}),`
241
+ `]}),`
242
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`cn("a b", "b", { c: true }); // "a b b c".
243
+ cn(["a", "b"] as never, "c"); // "c": массив проигнорирован.
244
+ `})}),`
245
+ `,(0,c.jsxs)(t.p,{children:[`Передавайте обычные object literals. Реализация обходит enumerable-ключи через `,(0,c.jsx)(t.code,{children:`for...in`}),`, поэтому объект с вручную настроенным prototype может добавить унаследованный enumerable-ключ.`]}),`
246
+ `,(0,c.jsx)(t.h3,{id:`classnames`,children:(0,c.jsx)(t.code,{children:`classNames`})}),`
247
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`classNames`}),` — deprecated-алиас той же функции `,(0,c.jsx)(t.code,{children:`cn`}),`:`]}),`
248
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { classNames } from "@ryuzaki13/react-foundation-lib/utils";
249
+ `})}),`
250
+ `,(0,c.jsxs)(t.p,{children:[`Новый код должен использовать `,(0,c.jsx)(t.code,{children:`cn`}),`. Алиас существует только для уже написанного consumer-кода и не предоставляет другого поведения.`]}),`
251
+ `,(0,c.jsx)(t.h2,{id:`как-выбрать-функцию-клонирования`,children:`Как выбрать функцию клонирования`}),`
252
+ `,(0,c.jsx)(t.p,{children:`В модуле есть две похожие функции. Они не взаимозаменяемы во всех сценариях.`}),`
253
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Свойство`}),(0,c.jsx)(t.th,{children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})}),(0,c.jsx)(t.th,{children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Основное назначение`}),(0,c.jsx)(t.td,{children:`Строгая data-only конфигурация`}),(0,c.jsx)(t.td,{children:`Более широкий JavaScript object graph`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Примитивы, массивы, plain object`}),(0,c.jsx)(t.td,{children:`да`}),(0,c.jsx)(t.td,{children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`Date`})}),(0,c.jsx)(t.td,{children:`да`}),(0,c.jsx)(t.td,{children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`RegExp`}),`, `,(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`})]}),(0,c.jsxs)(t.td,{children:[`нет, выбрасывает `,(0,c.jsx)(t.code,{children:`TypeError`})]}),(0,c.jsx)(t.td,{children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Циклические ссылки`}),(0,c.jsx)(t.td,{children:`да`}),(0,c.jsx)(t.td,{children:`да`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Функции в object`}),(0,c.jsx)(t.td,{children:`поле удаляется`}),(0,c.jsx)(t.td,{children:`data-свойство удаляется`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Функции в array по умолчанию`}),(0,c.jsxs)(t.td,{children:[`элемент удаляется, массив сжимается (`,(0,c.jsx)(t.code,{children:`"omit"`}),`)`]}),(0,c.jsxs)(t.td,{children:[`индекс остаётся со значением `,(0,c.jsx)(t.code,{children:`undefined`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Разреженные позиции массива`}),(0,c.jsxs)(t.td,{children:[`превращаются в явный `,(0,c.jsx)(t.code,{children:`undefined`})]}),(0,c.jsx)(t.td,{children:`сохраняются как пропущенные позиции`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Symbol и non-enumerable properties`}),(0,c.jsx)(t.td,{children:`не копируются`}),(0,c.jsx)(t.td,{children:`копируются`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Getter/setter`}),(0,c.jsx)(t.td,{children:`getter может быть вызван; значение копируется`}),(0,c.jsx)(t.td,{children:`accessor полностью пропускается и не вызывается`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Property descriptors`}),(0,c.jsx)(t.td,{children:`не сохраняются`}),(0,c.jsx)(t.td,{children:`сохраняются для data-свойств`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Prototype`}),(0,c.jsx)(t.td,{children:`результат — обычный объект`}),(0,c.jsx)(t.td,{children:`обычный объект или исходный prototype по опции`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`Неподдержанный специальный built-in`}),(0,c.jsxs)(t.td,{children:[`явный `,(0,c.jsx)(t.code,{children:`TypeError`})]}),(0,c.jsx)(t.td,{children:`поведение не гарантировано`})]})]})]}),`
254
+ `,(0,c.jsx)(t.p,{children:`Практическое правило:`}),`
255
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`сохраняемая конфигурация, DTO-like draft, Zustand snapshot
256
+
257
+
258
+ deepCopyWithoutFunctions
259
+
260
+ Map / Set / RegExp / descriptors / общий object graph
261
+
262
+
263
+ deepCloneWithoutFunctions
264
+ `})}),`
265
+ `,(0,c.jsx)(t.p,{children:`Если значения должны пережить JSON/localStorage/backend boundary, строгая функция обычно безопаснее: неподдерживаемый объект обнаружится сразу, а не превратится в объект с неожиданным поведением.`}),`
266
+ `,(0,c.jsx)(t.h2,{id:`deepcopywithoutfunctions`,children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})}),`
267
+ `,(0,c.jsx)(t.h3,{id:`назначение-1`,children:`Назначение`}),`
268
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),` создаёт независимую копию строгой data-only структуры и удаляет функции. Поддерживаются:`]}),`
269
+ `,(0,c.jsxs)(t.ul,{children:[`
270
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`null`}),`, `,(0,c.jsx)(t.code,{children:`undefined`}),`, строки, числа, `,(0,c.jsx)(t.code,{children:`boolean`}),`, `,(0,c.jsx)(t.code,{children:`bigint`}),`, `,(0,c.jsx)(t.code,{children:`symbol`}),` как корневые/вложенные примитивы;`]}),`
271
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Date`}),`;`]}),`
272
+ `,(0,c.jsx)(t.li,{children:`массивы;`}),`
273
+ `,(0,c.jsxs)(t.li,{children:[`plain objects с prototype `,(0,c.jsx)(t.code,{children:`Object.prototype`}),` или `,(0,c.jsx)(t.code,{children:`null`}),`;`]}),`
274
+ `,(0,c.jsx)(t.li,{children:`циклические ссылки и повторное использование одного массива/plain object.`}),`
275
+ `]}),`
276
+ `,(0,c.jsxs)(t.blockquote,{children:[`
277
+ `,(0,c.jsxs)(t.p,{children:[`Поддержка `,(0,c.jsx)(t.code,{children:`bigint`}),` и `,(0,c.jsx)(t.code,{children:`symbol`}),` клонированием не означает, что их затем сможет сериализовать JSON. `,(0,c.jsx)(t.code,{children:`stableStringify`}),` подчиняется ограничениям `,(0,c.jsx)(t.code,{children:`JSON.stringify`}),`.`]}),`
278
+ `]}),`
279
+ `,(0,c.jsx)(t.h3,{id:`базовый-пример`,children:`Базовый пример`}),`
280
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { deepCopyWithoutFunctions } from "@ryuzaki13/react-foundation-lib/utils";
281
+
282
+ const source = {
283
+ id: "REPORT-1",
284
+ title: " Мой отчёт ",
285
+ enabled: false,
286
+ filters: [{ field: "STATUS", values: [] }],
287
+ createdAt: new Date("2026-01-02T00:00:00.000Z"),
288
+ onOpen: () => undefined
289
+ };
290
+
291
+ const copy = deepCopyWithoutFunctions(source);
292
+
293
+ console.log(copy !== source); // true.
294
+ console.log(copy.filters !== source.filters); // true.
295
+ console.log(copy.filters[0] !== source.filters[0]); // true.
296
+ console.log(copy.createdAt !== source.createdAt); // true.
297
+ console.log("onOpen" in copy); // false.
298
+ `})}),`
299
+ `,(0,c.jsxs)(t.p,{children:[`Строка `,(0,c.jsx)(t.code,{children:`" Мой отчёт "`}),`, явный `,(0,c.jsx)(t.code,{children:`false`}),` и пустой массив сохраняются буквально.`]}),`
300
+ `,(0,c.jsx)(t.h3,{id:`функции-внутри-массива`,children:`Функции внутри массива`}),`
301
+ `,(0,c.jsxs)(t.p,{children:[`По умолчанию применяется стратегия `,(0,c.jsx)(t.code,{children:`"omit"`}),`: функция удаляется, а следующие элементы сдвигаются влево.`]}),`
302
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = deepCopyWithoutFunctions(["A", () => "skip", "C"]);
303
+
304
+ console.log(result); // ["A", "C"].
305
+ console.log(result.length); // 2.
306
+ `})}),`
307
+ `,(0,c.jsxs)(t.p,{children:[`Стратегия `,(0,c.jsx)(t.code,{children:`"undefined"`}),` сохраняет длину и индексы:`]}),`
308
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = deepCopyWithoutFunctions(["A", () => "skip", "C"], {
309
+ arrayFunctionStrategy: "undefined"
310
+ });
311
+
312
+ console.log(result); // ["A", undefined, "C"].
313
+ console.log(result.length); // 3.
314
+ `})}),`
315
+ `,(0,c.jsxs)(t.p,{children:[`Выбирайте `,(0,c.jsx)(t.code,{children:`"undefined"`}),`, если индекс имеет самостоятельное значение. Учитывайте, что JSON затем превратит `,(0,c.jsx)(t.code,{children:`undefined`}),` в массиве в `,(0,c.jsx)(t.code,{children:`null`}),`.`]}),`
316
+ `,(0,c.jsx)(t.h3,{id:`plain-object`,children:`Plain object`}),`
317
+ `,(0,c.jsxs)(t.p,{children:[`Plain object — обычный объект `,(0,c.jsx)(t.code,{children:`{}`}),` или объект без prototype:`]}),`
318
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const ordinary = { id: "A" };
319
+ const withoutPrototype = Object.create(null) as Record<string, unknown>;
320
+ `})}),`
321
+ `,(0,c.jsxs)(t.p,{children:[`Функция копирует только собственные enumerable string-свойства, возвращая обычный объект `,(0,c.jsx)(t.code,{children:`{}`}),`. Symbol-ключи, non-enumerable свойства и исходный prototype не сохраняются.`]}),`
322
+ `,(0,c.jsx)(t.p,{children:`Getter может быть вызван, потому что значение читается как обычное свойство:`}),`
323
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const source = {
324
+ get total() {
325
+ return 10;
326
+ }
327
+ };
328
+
329
+ const copy = deepCopyWithoutFunctions(source);
330
+ console.log(copy.total); // 10, теперь это обычное поле результата.
331
+ `})}),`
332
+ `,(0,c.jsx)(t.p,{children:`Не используйте getter с побочными эффектами в data-only конфигурациях.`}),`
333
+ `,(0,c.jsx)(t.h3,{id:`cycles-и-повторные-ссылки`,children:`Cycles и повторные ссылки`}),`
334
+ `,(0,c.jsx)(t.p,{children:`Для массивов и plain objects используется таблица уже скопированных ссылок. Поэтому цикл не вызывает бесконечную рекурсию:`}),`
335
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const source: { id: string; self?: unknown } = { id: "A" };
336
+ source.self = source;
337
+
338
+ const copy = deepCopyWithoutFunctions(source);
339
+
340
+ console.log(copy.self === copy); // true.
341
+ `})}),`
342
+ `,(0,c.jsx)(t.p,{children:`Если один вложенный plain object встречается в двух местах, в результате оба поля будут ссылаться на одну и ту же его копию.`}),`
343
+ `,(0,c.jsx)(t.h3,{id:`неподдерживаемые-объекты`,children:`Неподдерживаемые объекты`}),`
344
+ `,(0,c.jsxs)(t.p,{children:[`Функция выбрасывает `,(0,c.jsx)(t.code,{children:`TypeError`}),` для объектов, которые не являются `,(0,c.jsx)(t.code,{children:`Date`}),`, массивом или plain object:`]}),`
345
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`deepCopyWithoutFunctions(new Map());
346
+ // TypeError: Unsupported object for config clone: [object Map]
347
+ `})}),`
348
+ `,(0,c.jsx)(t.p,{children:`К неподдерживаемым значениям относятся, например:`}),`
349
+ `,(0,c.jsxs)(t.ul,{children:[`
350
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`}),`, `,(0,c.jsx)(t.code,{children:`RegExp`}),`;`]}),`
351
+ `,(0,c.jsx)(t.li,{children:`экземпляры пользовательских классов;`}),`
352
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`URL`}),`, `,(0,c.jsx)(t.code,{children:`Error`}),`, `,(0,c.jsx)(t.code,{children:`Promise`}),`, `,(0,c.jsx)(t.code,{children:`WeakMap`}),`;`]}),`
353
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`ArrayBuffer`}),` и typed arrays;`]}),`
354
+ `,(0,c.jsxs)(t.li,{children:[`browser `,(0,c.jsx)(t.code,{children:`Blob`}),`, `,(0,c.jsx)(t.code,{children:`File`}),` и DOM nodes.`]}),`
355
+ `]}),`
356
+ `,(0,c.jsx)(t.p,{children:`Не подавляйте такую ошибку без анализа. Она обычно сообщает, что в сериализуемую конфигурацию попал объект неправильного слоя.`}),`
357
+ `,(0,c.jsx)(t.h3,{id:`корневая-функция`,children:`Корневая функция`}),`
358
+ `,(0,c.jsxs)(t.p,{children:[`Если само входное значение является функцией, runtime-результат — `,(0,c.jsx)(t.code,{children:`undefined`}),`:`]}),`
359
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = deepCopyWithoutFunctions(() => "value");
360
+ console.log(result); // undefined.
361
+ `})}),`
362
+ `,(0,c.jsx)(t.p,{children:`Обычно корневая функция означает ошибочный вызов. Не полагайтесь на generic return type как на runtime-проверку.`}),`
363
+ `,(0,c.jsx)(t.h2,{id:`deepclonewithoutfunctions`,children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})}),`
364
+ `,(0,c.jsx)(t.h3,{id:`назначение-2`,children:`Назначение`}),`
365
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`}),` работает с более широким object graph. Помимо обычных объектов и массивов функция отдельно поддерживает:`]}),`
366
+ `,(0,c.jsxs)(t.ul,{children:[`
367
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Date`}),`;`]}),`
368
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`RegExp`}),`, включая `,(0,c.jsx)(t.code,{children:`lastIndex`}),`;`]}),`
369
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Map`}),`, включая клонирование ключей и значений;`]}),`
370
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Set`}),`;`]}),`
371
+ `,(0,c.jsx)(t.li,{children:`циклические ссылки;`}),`
372
+ `,(0,c.jsx)(t.li,{children:`symbol и non-enumerable data-свойства;`}),`
373
+ `,(0,c.jsx)(t.li,{children:`property descriptors;`}),`
374
+ `,(0,c.jsx)(t.li,{children:`опциональное сохранение prototype.`}),`
375
+ `]}),`
376
+ `,(0,c.jsx)(t.h3,{id:`базовый-пример-1`,children:`Базовый пример`}),`
377
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { deepCloneWithoutFunctions } from "@ryuzaki13/react-foundation-lib/utils";
378
+
379
+ const source: Record<string, unknown> = {
380
+ pattern: /order/gi,
381
+ lookup: new Map([["A", { title: "Первая" }]]),
382
+ selected: new Set(["A", "B"]),
383
+ onReset: () => undefined
384
+ };
385
+ source.self = source;
386
+
387
+ const clone = deepCloneWithoutFunctions(source);
388
+
389
+ console.log(clone !== source); // true.
390
+ console.log(clone.self === clone); // true.
391
+ console.log(clone.lookup !== source.lookup); // true.
392
+ console.log("onReset" in clone); // false.
393
+ `})}),`
394
+ `,(0,c.jsx)(t.h3,{id:`массивы-значение-по-умолчанию`,children:`Массивы: значение по умолчанию`}),`
395
+ `,(0,c.jsxs)(t.p,{children:[`В отличие от `,(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),`, здесь default-стратегия сохраняет индекс и записывает `,(0,c.jsx)(t.code,{children:`undefined`}),` вместо функции:`]}),`
396
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = deepCloneWithoutFunctions(["A", () => "skip", "C"]);
397
+
398
+ console.log(result); // ["A", undefined, "C"].
399
+ console.log(result.length); // 3.
400
+ `})}),`
401
+ `,(0,c.jsxs)(t.p,{children:[`Чтобы удалить функции и сжать массив, передайте `,(0,c.jsx)(t.code,{children:`"omit"`}),`:`]}),`
402
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = deepCloneWithoutFunctions(["A", () => "skip", "C"], {
403
+ arrayFunctionStrategy: "omit"
404
+ });
405
+
406
+ console.log(result); // ["A", "C"].
407
+ `})}),`
408
+ `,(0,c.jsx)(t.p,{children:`Default-режим сохраняет настоящие «дыры» разреженного массива:`}),`
409
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const source = ["A", , "C"];
410
+ const clone = deepCloneWithoutFunctions(source);
411
+
412
+ console.log(clone.length); // 3.
413
+ console.log(1 in clone); // false.
414
+ `})}),`
415
+ `,(0,c.jsxs)(t.p,{children:[`В режиме `,(0,c.jsx)(t.code,{children:`"omit"`}),` все существующие нефункциональные элементы уплотняются, поэтому исходные индексы больше не сохраняются.`]}),`
416
+ `,(0,c.jsx)(t.h3,{id:`map`,children:(0,c.jsx)(t.code,{children:`Map`})}),`
417
+ `,(0,c.jsx)(t.p,{children:`Клонируются и ключи, и значения:`}),`
418
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const key = { id: "A" };
419
+ const source = new Map([[key, { title: "Запись" }]]);
420
+ const clone = deepCloneWithoutFunctions(source);
421
+
422
+ console.log(clone.has(key)); // false: исходный object key был скопирован.
423
+ console.log([...clone.keys()][0] === key); // false.
424
+ `})}),`
425
+ `,(0,c.jsx)(t.p,{children:`Если ключ или значение пары является функцией, вся пара пропускается.`}),`
426
+ `,(0,c.jsx)(t.h3,{id:`set`,children:(0,c.jsx)(t.code,{children:`Set`})}),`
427
+ `,(0,c.jsx)(t.p,{children:`Каждый элемент клонируется. Элементы-функции пропускаются:`}),`
428
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const clone = deepCloneWithoutFunctions(new Set([1, () => 2, 3]));
429
+
430
+ console.log([...clone]); // [1, 3].
431
+ `})}),`
432
+ `,(0,c.jsx)(t.h3,{id:`descriptors-symbols-и-accessors`,children:`Descriptors, symbols и accessors`}),`
433
+ `,(0,c.jsxs)(t.p,{children:[`Для обычного объекта обходятся все собственные ключи через `,(0,c.jsx)(t.code,{children:`Reflect.ownKeys`}),`, включая symbols и non-enumerable properties. Для data-свойства сохраняются флаги `,(0,c.jsx)(t.code,{children:`enumerable`}),`, `,(0,c.jsx)(t.code,{children:`writable`}),` и `,(0,c.jsx)(t.code,{children:`configurable`}),`.`]}),`
434
+ `,(0,c.jsx)(t.p,{children:`Getter/setter-свойства полностью пропускаются: getter не вызывается, но accessor также не переносится в clone.`}),`
435
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`let calls = 0;
436
+ const source = {
437
+ get computed() {
438
+ calls += 1;
439
+ return 10;
440
+ }
441
+ };
442
+
443
+ const clone = deepCloneWithoutFunctions(source);
444
+
445
+ console.log(calls); // 0.
446
+ console.log("computed" in clone); // false.
447
+ `})}),`
448
+ `,(0,c.jsx)(t.h3,{id:`preserveprototype`,children:(0,c.jsx)(t.code,{children:`preservePrototype`})}),`
449
+ `,(0,c.jsx)(t.p,{children:`По умолчанию generic object превращается в plain object:`}),`
450
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`class Model {
451
+ value = 1;
452
+ }
453
+
454
+ const source = new Model();
455
+ const plain = deepCloneWithoutFunctions(source);
456
+
457
+ console.log(plain instanceof Model); // false.
458
+ `})}),`
459
+ `,(0,c.jsxs)(t.p,{children:[`Опция `,(0,c.jsx)(t.code,{children:`preservePrototype: true`}),` создаёт результат с тем же prototype:`]}),`
460
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const clone = deepCloneWithoutFunctions(source, {
461
+ preservePrototype: true
462
+ });
463
+
464
+ console.log(clone instanceof Model); // true.
465
+ `})}),`
466
+ `,(0,c.jsxs)(t.p,{children:[`Это не вызывает constructor и не восстанавливает private fields или внутренние слоты платформенных объектов. `,(0,c.jsx)(t.code,{children:`instanceof === true`}),` не доказывает, что экземпляр полностью работоспособен.`]}),`
467
+ `,(0,c.jsx)(t.h3,{id:`граница-поддерживаемых-built-ins`,children:`Граница поддерживаемых built-ins`}),`
468
+ `,(0,c.jsxs)(t.p,{children:[`Специальная корректная логика есть только для `,(0,c.jsx)(t.code,{children:`Date`}),`, `,(0,c.jsx)(t.code,{children:`RegExp`}),`, `,(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`}),`, массивов и generic objects. Для `,(0,c.jsx)(t.code,{children:`URL`}),`, `,(0,c.jsx)(t.code,{children:`Error`}),`, `,(0,c.jsx)(t.code,{children:`Promise`}),`, `,(0,c.jsx)(t.code,{children:`WeakMap`}),`, `,(0,c.jsx)(t.code,{children:`ArrayBuffer`}),`, typed arrays, `,(0,c.jsx)(t.code,{children:`Blob`}),`, `,(0,c.jsx)(t.code,{children:`File`}),` и DOM nodes поведение не является поддерживаемым контрактом. Они могут превратиться в внешне похожий, но неработоспособный объект без внутренних slots.`]}),`
469
+ `,(0,c.jsx)(t.p,{children:`Для таких типов используйте специализированный способ копирования или явно преобразуйте значение в data-only representation.`}),`
470
+ `,(0,c.jsxs)(t.h3,{id:`ограничение-повторных-date-и-regexp`,children:[`Ограничение повторных `,(0,c.jsx)(t.code,{children:`Date`}),` и `,(0,c.jsx)(t.code,{children:`RegExp`})]}),`
471
+ `,(0,c.jsxs)(t.p,{children:[`Сами containers участвуют в восстановлении повторных ссылок и cycles. `,(0,c.jsx)(t.code,{children:`Date`}),` и `,(0,c.jsx)(t.code,{children:`RegExp`}),` копируются как отдельные значения до регистрации в таблице ссылок. Если один и тот же экземпляр `,(0,c.jsx)(t.code,{children:`Date`}),`/`,(0,c.jsx)(t.code,{children:`RegExp`}),` находится в нескольких полях, каждое поле может получить отдельную эквивалентную копию.`]}),`
472
+ `,(0,c.jsx)(t.h2,{id:`clone-не-является-normalize`,children:`Clone не является normalize`}),`
473
+ `,(0,c.jsx)(t.p,{children:`Обе функции клонирования создают независимую структуру и удаляют функции. Они не должны использоваться как скрытая нормализация пользовательского draft.`}),`
474
+ `,(0,c.jsx)(t.p,{children:`Клонирование сохраняет:`}),`
475
+ `,(0,c.jsxs)(t.ul,{children:[`
476
+ `,(0,c.jsx)(t.li,{children:`пробелы в начале и конце строк;`}),`
477
+ `,(0,c.jsxs)(t.li,{children:[`пустую строку `,(0,c.jsx)(t.code,{children:`""`}),`;`]}),`
478
+ `,(0,c.jsxs)(t.li,{children:[`явный `,(0,c.jsx)(t.code,{children:`false`}),`;`]}),`
479
+ `,(0,c.jsx)(t.li,{children:`пустые массивы и объекты;`}),`
480
+ `,(0,c.jsx)(t.li,{children:`дубликаты;`}),`
481
+ `,(0,c.jsx)(t.li,{children:`порядок элементов;`}),`
482
+ `,(0,c.jsx)(t.li,{children:`исходные строковые значения.`}),`
483
+ `]}),`
484
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const draft = {
485
+ title: "Новая группа ",
486
+ visible: false,
487
+ tags: ["A", "A", ""],
488
+ columns: []
489
+ };
490
+
491
+ const copy = deepCopyWithoutFunctions(draft);
492
+
493
+ console.log(copy);
494
+ // {
495
+ // title: "Новая группа ",
496
+ // visible: false,
497
+ // tags: ["A", "A", ""],
498
+ // columns: []
499
+ // }
500
+ `})}),`
501
+ `,(0,c.jsxs)(t.p,{children:[`Если приложению нужна canonical save-форма, выполняйте отдельный явно названный `,(0,c.jsx)(t.code,{children:`normalize...`}),` на границе сохранения или восстановления:`]}),`
502
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`пользовательский ввод
503
+
504
+
505
+ literal draft ── clone ──► literal draft copy
506
+
507
+ │ только команда save
508
+
509
+ normalizeForSave(draft) ──► canonical snapshot
510
+ `})}),`
511
+ `,(0,c.jsx)(t.p,{children:`Не записывайте нормализованный snapshot обратно в редактируемый draft без отдельного пользовательского действия.`}),`
512
+ `,(0,c.jsx)(t.h2,{id:`stablestringify`,children:(0,c.jsx)(t.code,{children:`stableStringify`})}),`
513
+ `,(0,c.jsx)(t.h3,{id:`назначение-3`,children:`Назначение`}),`
514
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`stableStringify`}),` вызывает JSON-сериализацию, но перед этим сортирует string-ключи каждого объекта по алфавиту. Поэтому одинаковые JSON-compatible структуры дают одинаковую строку независимо от порядка добавления полей.`]}),`
515
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { stableStringify } from "@ryuzaki13/react-foundation-lib/utils";
516
+
517
+ const first = { b: 2, a: { d: 4, c: 3 } };
518
+ const second = { a: { c: 3, d: 4 }, b: 2 };
519
+
520
+ console.log(stableStringify(first));
521
+ // '{"a":{"c":3,"d":4},"b":2}'
522
+
523
+ console.log(stableStringify(first) === stableStringify(second));
524
+ // true.
525
+ `})}),`
526
+ `,(0,c.jsx)(t.h3,{id:`что-сортируется`,children:`Что сортируется`}),`
527
+ `,(0,c.jsxs)(t.ul,{children:[`
528
+ `,(0,c.jsx)(t.li,{children:`Ключи каждого объекта сортируются лексикографически.`}),`
529
+ `,(0,c.jsx)(t.li,{children:`Вложенные объекты обрабатываются рекурсивно.`}),`
530
+ `,(0,c.jsx)(t.li,{children:`Порядок элементов массивов сохраняется.`}),`
531
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`Date`}),` сериализуется стандартным JSON-механизмом в ISO-строку.`]}),`
532
+ `]}),`
533
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`stableStringify({ list: [{ z: 1, a: 2 }], order: ["B", "A"] });
534
+ // '{"list":[{"a":2,"z":1}],"order":["B","A"]}'
535
+ `})}),`
536
+ `,(0,c.jsx)(t.h3,{id:`когда-использовать`,children:`Когда использовать`}),`
537
+ `,(0,c.jsx)(t.p,{children:`Подходящие сценарии:`}),`
538
+ `,(0,c.jsxs)(t.ul,{children:[`
539
+ `,(0,c.jsx)(t.li,{children:`стабильная часть cache/query key, если структура полностью JSON-compatible;`}),`
540
+ `,(0,c.jsx)(t.li,{children:`сравнение двух небольших data-only snapshots;`}),`
541
+ `,(0,c.jsx)(t.li,{children:`обнаружение изменения serializable form state;`}),`
542
+ `,(0,c.jsx)(t.li,{children:`стабильный ключ memoization на доверенных данных.`}),`
543
+ `]}),`
544
+ `,(0,c.jsxs)(t.p,{children:[`Для TanStack Query сначала предпочитайте структурный query key-массив. `,(0,c.jsx)(t.code,{children:`stableStringify`}),` нужен только там, где consumer действительно требует строку.`]}),`
545
+ `,(0,c.jsx)(t.h3,{id:`ограничения-стандартного-json`,children:`Ограничения стандартного JSON`}),`
546
+ `,(0,c.jsxs)(t.p,{children:[`Функция наследует семантику `,(0,c.jsx)(t.code,{children:`JSON.stringify`}),`:`]}),`
547
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Значение`}),(0,c.jsx)(t.th,{children:`Результат`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`undefined`}),`, function, symbol в object`]}),(0,c.jsx)(t.td,{children:`свойство пропускается`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`undefined`}),`, function, symbol в array`]}),(0,c.jsxs)(t.td,{children:[`элемент становится `,(0,c.jsx)(t.code,{children:`null`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`NaN`}),`, `,(0,c.jsx)(t.code,{children:`Infinity`}),`, `,(0,c.jsx)(t.code,{children:`-Infinity`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`null`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`Date`})}),(0,c.jsx)(t.td,{children:`ISO-строка`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Set`}),` без enumerable string fields`]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`{}`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`bigint`})}),(0,c.jsxs)(t.td,{children:[`выбрасывается `,(0,c.jsx)(t.code,{children:`TypeError`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`circular reference`}),(0,c.jsxs)(t.td,{children:[`выбрасывается `,(0,c.jsx)(t.code,{children:`TypeError`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsxs)(t.td,{children:[`object с `,(0,c.jsx)(t.code,{children:`toJSON`})]}),(0,c.jsxs)(t.td,{children:[`вызывается `,(0,c.jsx)(t.code,{children:`toJSON`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:`getter enumerable-свойства`}),(0,c.jsx)(t.td,{children:`getter может быть вызван`})]})]})]}),`
548
+ `,(0,c.jsx)(t.p,{children:`Из-за этих правил разные JavaScript-значения иногда дают одинаковую строку:`}),`
549
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`stableStringify({ value: undefined }); // "{}".
550
+ stableStringify({}); // "{}".
551
+ `})}),`
552
+ `,(0,c.jsx)(t.p,{children:`Не используйте строку как доказательство полной идентичности произвольных объектов.`}),`
553
+ `,(0,c.jsxs)(t.h3,{id:`корневое-undefined`,children:[`Корневое `,(0,c.jsx)(t.code,{children:`undefined`})]}),`
554
+ `,(0,c.jsxs)(t.p,{children:[`Публичная TypeScript-сигнатура указывает `,(0,c.jsx)(t.code,{children:`string`}),`, но стандартный `,(0,c.jsx)(t.code,{children:`JSON.stringify`}),` возвращает runtime `,(0,c.jsx)(t.code,{children:`undefined`}),` для корневых `,(0,c.jsx)(t.code,{children:`undefined`}),`, function и symbol.`]}),`
555
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const result = stableStringify(undefined);
556
+ console.log(result); // undefined во время выполнения.
557
+ `})}),`
558
+ `,(0,c.jsxs)(t.p,{children:[`Передавайте JSON-compatible top-level value: объект, массив, строку, число, `,(0,c.jsx)(t.code,{children:`boolean`}),` или `,(0,c.jsx)(t.code,{children:`null`}),`.`]}),`
559
+ `,(0,c.jsx)(t.h3,{id:`не-security-canonicalization`,children:`Не security canonicalization`}),`
560
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`stableStringify`}),` не является криптографической canonical JSON-реализацией. Не используйте его напрямую для цифровых подписей, security tokens, authorization или сериализации недоверенного объекта с getters/`,(0,c.jsx)(t.code,{children:`toJSON`}),`.`]}),`
561
+ `,(0,c.jsxs)(t.h2,{id:`tobase64-и-encodebase64`,children:[(0,c.jsx)(t.code,{children:`toBase64`}),` и `,(0,c.jsx)(t.code,{children:`encodeBase64`})]}),`
562
+ `,(0,c.jsx)(t.h3,{id:`назначение-4`,children:`Назначение`}),`
563
+ `,(0,c.jsx)(t.p,{children:`Обе функции кодируют JavaScript-строку в UTF-8-байты, а затем в стандартный Base64:`}),`
564
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { toBase64 } from "@ryuzaki13/react-foundation-lib/utils";
565
+
566
+ const value = toBase64("Привет");
567
+ console.log(value); // 0J/RgNC40LLQtdGC
568
+ `})}),`
569
+ `,(0,c.jsxs)(t.p,{children:[`В отличие от прямого `,(0,c.jsx)(t.code,{children:`btoa("Привет")`}),`, Unicode-текст не теряется.`]}),`
570
+ `,(0,c.jsx)(t.h3,{id:`какую-функцию-выбрать`,children:`Какую функцию выбрать`}),`
571
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`API`}),(0,c.jsx)(t.th,{children:`Способ преобразования текста в байты`}),(0,c.jsx)(t.th,{children:`Рекомендация`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`toBase64`})}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`TextEncoder`}),`, затем `,(0,c.jsx)(t.code,{children:`btoa`})]}),(0,c.jsx)(t.td,{children:`Предпочитать для нового browser-кода`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`encodeBase64`})}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`encodeURIComponent`}),`, percent bytes, затем `,(0,c.jsx)(t.code,{children:`btoa`})]}),(0,c.jsx)(t.td,{children:`Использовать для существующего совместимого кода`})]})]})]}),`
572
+ `,(0,c.jsxs)(t.p,{children:[`Для одиночного некорректного UTF-16 surrogate поведение различается: `,(0,c.jsx)(t.code,{children:`TextEncoder`}),` заменяет его replacement character, а `,(0,c.jsx)(t.code,{children:`encodeURIComponent`}),` может выбросить `,(0,c.jsx)(t.code,{children:`URIError`}),`.`]}),`
573
+ `,(0,c.jsx)(t.h3,{id:`декодирование`,children:`Декодирование`}),`
574
+ `,(0,c.jsx)(t.p,{children:`Модуль не экспортирует decoder. В браузере UTF-8 Base64 можно декодировать так:`}),`
575
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`function decodeBase64(value: string): string {
576
+ const binary = atob(value);
577
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
578
+
579
+ return new TextDecoder().decode(bytes);
580
+ }
581
+
582
+ const original = decodeBase64(toBase64("Привет"));
583
+ console.log(original); // "Привет".
584
+ `})}),`
585
+ `,(0,c.jsx)(t.h3,{id:`важные-ограничения`,children:`Важные ограничения`}),`
586
+ `,(0,c.jsxs)(t.ul,{children:[`
587
+ `,(0,c.jsxs)(t.li,{children:[`Результат — обычный Base64 с символами `,(0,c.jsx)(t.code,{children:`+`}),`, `,(0,c.jsx)(t.code,{children:`/`}),` и padding `,(0,c.jsx)(t.code,{children:`=`}),`; это не Base64URL.`]}),`
588
+ `,(0,c.jsx)(t.li,{children:`Base64 не шифрует и не скрывает содержимое.`}),`
589
+ `,(0,c.jsx)(t.li,{children:`Размер строки обычно увеличивается примерно на треть относительно количества байтов.`}),`
590
+ `,(0,c.jsxs)(t.li,{children:[`API предназначен для текста, а не для произвольного `,(0,c.jsx)(t.code,{children:`Blob`}),`/`,(0,c.jsx)(t.code,{children:`ArrayBuffer`}),`.`]}),`
591
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`toBase64("")`}),` и `,(0,c.jsx)(t.code,{children:`encodeBase64("")`}),` возвращают пустую строку.`]}),`
592
+ `,(0,c.jsx)(t.li,{children:`Для работы нужны соответствующие global browser APIs.`}),`
593
+ `]}),`
594
+ `,(0,c.jsxs)(t.p,{children:[`Если нужно преобразовать Base64/binary payload в `,(0,c.jsx)(t.code,{children:`Blob`}),`, используйте `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/binary`}),`.`]}),`
595
+ `,(0,c.jsx)(t.h2,{id:`клавиатурная-активация`,children:`Клавиатурная активация`}),`
596
+ `,(0,c.jsx)(t.h3,{id:`keyboardactivationkeys`,children:(0,c.jsx)(t.code,{children:`keyboardActivationKeys`})}),`
597
+ `,(0,c.jsxs)(t.p,{children:[`Readonly tuple содержит точные значения `,(0,c.jsx)(t.code,{children:`KeyboardEvent.key`}),`, которые активируют элемент с поведением кнопки:`]}),`
598
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { keyboardActivationKeys } from "@ryuzaki13/react-foundation-lib/utils";
599
+
600
+ console.log(keyboardActivationKeys); // ["Enter", " "].
601
+ `})}),`
602
+ `,(0,c.jsxs)(t.p,{children:[`Пробел представлен строкой из одного символа `,(0,c.jsx)(t.code,{children:`" "`}),`, а не словами `,(0,c.jsx)(t.code,{children:`"Space"`}),` или `,(0,c.jsx)(t.code,{children:`"Spacebar"`}),`.`]}),`
603
+ `,(0,c.jsx)(t.p,{children:`Тип:`}),`
604
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type KeyboardActivationKey = "Enter" | " ";
605
+ `})}),`
606
+ `,(0,c.jsx)(t.h3,{id:`iskeyboardactivationkey`,children:(0,c.jsx)(t.code,{children:`isKeyboardActivationKey`})}),`
607
+ `,(0,c.jsx)(t.p,{children:`Функция возвращает type guard:`}),`
608
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`function onKey(key: string) {
609
+ if (isKeyboardActivationKey(key)) {
610
+ // Здесь TypeScript знает: key — "Enter" | " ".
611
+ }
612
+ }
613
+ `})}),`
614
+ `,(0,c.jsx)(t.p,{children:`Точные результаты:`}),`
615
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`isKeyboardActivationKey("Enter"); // true.
616
+ isKeyboardActivationKey(" "); // true.
617
+ isKeyboardActivationKey("Spacebar"); // false.
618
+ isKeyboardActivationKey("Escape"); // false.
619
+ `})}),`
620
+ `,(0,c.jsx)(t.h3,{id:`handlekeyboardactivation`,children:(0,c.jsx)(t.code,{children:`handleKeyboardActivation`})}),`
621
+ `,(0,c.jsxs)(t.p,{children:[`Функция объединяет проверку клавиши, `,(0,c.jsx)(t.code,{children:`preventDefault()`}),` и вызов действия:`]}),`
622
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`import { handleKeyboardActivation } from "@ryuzaki13/react-foundation-lib/utils";
623
+
624
+ type CustomButtonProps = {
625
+ disabled?: boolean;
626
+ onActivate: () => void;
627
+ };
628
+
629
+ export function CustomButton({ disabled = false, onActivate }: CustomButtonProps) {
630
+ return (
631
+ <div
632
+ aria-disabled={disabled || undefined}
633
+ onClick={disabled ? undefined : onActivate}
634
+ onKeyDown={(event) => {
635
+ handleKeyboardActivation(event, onActivate, { disabled });
636
+ }}
637
+ role="button"
638
+ tabIndex={disabled ? -1 : 0}>
639
+ Открыть
640
+ </div>
641
+ );
642
+ }
643
+ `})}),`
644
+ `,(0,c.jsx)(t.p,{children:`Алгоритм:`}),`
645
+ `,(0,c.jsxs)(t.ol,{children:[`
646
+ `,(0,c.jsxs)(t.li,{children:[`Если `,(0,c.jsx)(t.code,{children:`disabled === true`}),`, возвращает `,(0,c.jsx)(t.code,{children:`false`}),` и ничего не делает.`]}),`
647
+ `,(0,c.jsxs)(t.li,{children:[`Если клавиша не `,(0,c.jsx)(t.code,{children:`Enter`}),` и не пробел, возвращает `,(0,c.jsx)(t.code,{children:`false`}),`.`]}),`
648
+ `,(0,c.jsxs)(t.li,{children:[`Вызывает `,(0,c.jsx)(t.code,{children:`event.preventDefault()`}),`.`]}),`
649
+ `,(0,c.jsxs)(t.li,{children:[`Синхронно вызывает `,(0,c.jsx)(t.code,{children:`action()`}),`.`]}),`
650
+ `,(0,c.jsxs)(t.li,{children:[`Возвращает `,(0,c.jsx)(t.code,{children:`true`}),`.`]}),`
651
+ `]}),`
652
+ `,(0,c.jsxs)(t.p,{children:[`Исключение из `,(0,c.jsx)(t.code,{children:`action`}),` не перехватывается.`]}),`
653
+ `,(0,c.jsxs)(t.blockquote,{children:[`
654
+ `,(0,c.jsxs)(t.p,{children:[`Для обычного `,(0,c.jsx)(t.code,{children:`<button>`}),` используйте нативное поведение браузера и `,(0,c.jsx)(t.code,{children:`onClick`}),`. Helper предназначен для обоснованных кастомных controls. Добавление собственного Enter/Space handler к `,(0,c.jsx)(t.code,{children:`<button>`}),` может привести к двойной активации.`]}),`
655
+ `]}),`
656
+ `,(0,c.jsxs)(t.p,{children:[`Helper не добавляет `,(0,c.jsx)(t.code,{children:`role`}),`, `,(0,c.jsx)(t.code,{children:`tabIndex`}),`, ARIA-состояния и обработчик click автоматически. Доступность всего компонента остаётся ответственностью host.`]}),`
657
+ `,(0,c.jsx)(t.h2,{id:`roving-focus`,children:`Roving focus`}),`
658
+ `,(0,c.jsx)(t.h3,{id:`что-это-такое`,children:`Что это такое`}),`
659
+ `,(0,c.jsxs)(t.p,{children:[`Roving focus — паттерн для составного control (`,(0,c.jsx)(t.code,{children:`Tabs`}),`, `,(0,c.jsx)(t.code,{children:`RadioGroup`}),`, toolbar): только один элемент имеет `,(0,c.jsx)(t.code,{children:`tabIndex={0}`}),`, остальные `,(0,c.jsx)(t.code,{children:`tabIndex={-1}`}),`. Arrow/Home/End меняют активный индекс, после чего host переводит DOM-фокус.`]}),`
660
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`}),` только вычисляет индекс. Функция не хранит state и не вызывает `,(0,c.jsx)(t.code,{children:`.focus()`}),`.`]}),`
661
+ `,(0,c.jsx)(t.h3,{id:`сигнатура-1`,children:`Сигнатура`}),`
662
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`interface RovingFocusTargetOptions {
663
+ currentIndex: number;
664
+ itemCount: number;
665
+ key: string;
666
+ orientation: "horizontal" | "vertical";
667
+ wrap?: boolean;
668
+ }
669
+
670
+ function getRovingFocusTargetIndex(options: RovingFocusTargetOptions): number | null;
671
+ `})}),`
672
+ `,(0,c.jsx)(t.h3,{id:`клавиши`,children:`Клавиши`}),`
673
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Orientation`}),(0,c.jsx)(t.th,{children:`Предыдущий элемент`}),(0,c.jsx)(t.th,{children:`Следующий элемент`}),(0,c.jsx)(t.th,{children:`Начало`}),(0,c.jsx)(t.th,{children:`Конец`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`horizontal`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ArrowLeft`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ArrowRight`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`Home`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`End`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`vertical`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ArrowUp`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ArrowDown`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`Home`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`End`})})]})]})]}),`
674
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`Home`}),` и `,(0,c.jsx)(t.code,{children:`End`}),` работают в обеих ориентациях.`]}),`
675
+ `,(0,c.jsx)(t.h3,{id:`пример-расчёта`,children:`Пример расчёта`}),`
676
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const target = getRovingFocusTargetIndex({
677
+ currentIndex: 1,
678
+ itemCount: 4,
679
+ key: "ArrowRight",
680
+ orientation: "horizontal"
681
+ });
682
+
683
+ console.log(target); // 2.
684
+ `})}),`
685
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`wrap`}),` по умолчанию равен `,(0,c.jsx)(t.code,{children:`true`}),`:`]}),`
686
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`getRovingFocusTargetIndex({
687
+ currentIndex: 3,
688
+ itemCount: 4,
689
+ key: "ArrowRight",
690
+ orientation: "horizontal"
691
+ });
692
+ // 0: переход с конца в начало.
693
+ `})}),`
694
+ `,(0,c.jsxs)(t.p,{children:[`При `,(0,c.jsx)(t.code,{children:`wrap: false`}),` на границе возвращается текущая крайняя позиция:`]}),`
695
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`getRovingFocusTargetIndex({
696
+ currentIndex: 3,
697
+ itemCount: 4,
698
+ key: "ArrowRight",
699
+ orientation: "horizontal",
700
+ wrap: false
701
+ });
702
+ // 3.
703
+ `})}),`
704
+ `,(0,c.jsx)(t.h3,{id:`граничные-случаи`,children:`Граничные случаи`}),`
705
+ `,(0,c.jsxs)(t.ul,{children:[`
706
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`itemCount <= 0`}),` возвращает `,(0,c.jsx)(t.code,{children:`null`}),`.`]}),`
707
+ `,(0,c.jsxs)(t.li,{children:[`Необрабатываемая клавиша возвращает `,(0,c.jsx)(t.code,{children:`null`}),`.`]}),`
708
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`currentIndex`}),` меньше `,(0,c.jsx)(t.code,{children:`0`}),` при положительном `,(0,c.jsx)(t.code,{children:`itemCount`}),` прижимается к `,(0,c.jsx)(t.code,{children:`0`}),`.`]}),`
709
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`currentIndex`}),` больше последнего индекса прижимается к последнему индексу.`]}),`
710
+ `,(0,c.jsxs)(t.li,{children:[`Передавайте целые конечные `,(0,c.jsx)(t.code,{children:`currentIndex`}),` и `,(0,c.jsx)(t.code,{children:`itemCount`}),`; функция не является validator для `,(0,c.jsx)(t.code,{children:`NaN`}),` и дробей.`]}),`
711
+ `]}),`
712
+ `,(0,c.jsx)(t.h3,{id:`react-применение`,children:`React-применение`}),`
713
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`const targetIndex = getRovingFocusTargetIndex({
714
+ currentIndex: activeIndex,
715
+ itemCount: tabs.length,
716
+ key: event.key,
717
+ orientation: "horizontal"
718
+ });
719
+
720
+ if (targetIndex !== null) {
721
+ event.preventDefault();
722
+ setActiveIndex(targetIndex);
723
+ tabRefs.current[targetIndex]?.focus();
724
+ }
725
+ `})}),`
726
+ `,(0,c.jsxs)(t.p,{children:[`Если в группе есть disabled-элементы, одного `,(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`}),` недостаточно: используйте select-navigation helpers или дополнительный поиск enabled-индекса.`]}),`
727
+ `,(0,c.jsx)(t.h2,{id:`навигация-по-доступным-опциям`,children:`Навигация по доступным опциям`}),`
728
+ `,(0,c.jsx)(t.p,{children:`Эти функции работают с обычным readonly-массивом и callback, который отвечает на вопрос «эта опция disabled?».`}),`
729
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type Option = {
730
+ id: string;
731
+ label: string;
732
+ disabled?: boolean;
733
+ };
734
+
735
+ const options: Option[] = [
736
+ { id: "A", label: "Первая" },
737
+ { id: "B", label: "Вторая", disabled: true },
738
+ { id: "C", label: "Третья" }
739
+ ];
740
+
741
+ const getDisabled = (option: Option) => option.disabled === true;
742
+ `})}),`
743
+ `,(0,c.jsx)(t.h3,{id:`findfirstenabledindex`,children:(0,c.jsx)(t.code,{children:`findFirstEnabledIndex`})}),`
744
+ `,(0,c.jsxs)(t.p,{children:[`Возвращает индекс первой enabled-опции или `,(0,c.jsx)(t.code,{children:`-1`}),`:`]}),`
745
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`findFirstEnabledIndex(options, getDisabled); // 0.
746
+ findFirstEnabledIndex([], getDisabled); // -1.
747
+ `})}),`
748
+ `,(0,c.jsx)(t.p,{children:`Если callback не передан, все элементы считаются enabled.`}),`
749
+ `,(0,c.jsx)(t.h3,{id:`findlastenabledindex`,children:(0,c.jsx)(t.code,{children:`findLastEnabledIndex`})}),`
750
+ `,(0,c.jsxs)(t.p,{children:[`Возвращает индекс последней enabled-опции или `,(0,c.jsx)(t.code,{children:`-1`}),`:`]}),`
751
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`findLastEnabledIndex(options, getDisabled); // 2.
752
+ `})}),`
753
+ `,(0,c.jsxs)(t.p,{children:[`Для пустого списка или списка, где все элементы disabled, возвращается `,(0,c.jsx)(t.code,{children:`-1`}),`.`]}),`
754
+ `,(0,c.jsx)(t.h3,{id:`findnextenabledindex`,children:(0,c.jsx)(t.code,{children:`findNextEnabledIndex`})}),`
755
+ `,(0,c.jsx)(t.p,{children:`Ищет enabled-опцию после текущей позиции:`}),`
756
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`findNextEnabledIndex(options, 0, 1, getDisabled);
757
+ // 2: движение вперёд, disabled индекс 1 пропущен.
758
+ `})}),`
759
+ `,(0,c.jsx)(t.p,{children:`Аргументы:`}),`
760
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{style:{textAlign:`right`},children:`Позиция`}),(0,c.jsx)(t.th,{children:`Аргумент`}),(0,c.jsx)(t.th,{children:`Значение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{style:{textAlign:`right`},children:`1`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`options`})}),(0,c.jsx)(t.td,{children:`readonly-массив опций`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{style:{textAlign:`right`},children:`2`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`currentIndex`})}),(0,c.jsxs)(t.td,{children:[`текущий индекс; для отсутствующей позиции обычно `,(0,c.jsx)(t.code,{children:`-1`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{style:{textAlign:`right`},children:`3`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`step`})}),(0,c.jsxs)(t.td,{children:[`только `,(0,c.jsx)(t.code,{children:`1`}),` вперёд или `,(0,c.jsx)(t.code,{children:`-1`}),` назад`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{style:{textAlign:`right`},children:`4`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`getOptionDisabled`})}),(0,c.jsx)(t.td,{children:`callback; truthy означает disabled`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{style:{textAlign:`right`},children:`5`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`optionsConfig`})}),(0,c.jsxs)(t.td,{children:[`объект `,(0,c.jsx)(t.code,{children:`{ wrap?: boolean }`}),`; default `,(0,c.jsx)(t.code,{children:`wrap`}),` — `,(0,c.jsx)(t.code,{children:`false`})]})]})]})]}),`
761
+ `,(0,c.jsx)(t.p,{children:`С циклическим переходом:`}),`
762
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`findNextEnabledIndex(options, 2, 1, getDisabled, { wrap: true });
763
+ // 0: после конца поиск продолжается с начала.
764
+ `})}),`
765
+ `,(0,c.jsxs)(t.p,{children:[`Если следующей опции нет и `,(0,c.jsx)(t.code,{children:`wrap === false`}),`, возвращается текущий валидный индекс. Если текущий индекс не входит в массив, возвращается `,(0,c.jsx)(t.code,{children:`-1`}),`.`]}),`
766
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`findNextEnabledIndex(options, 2, 1, getDisabled); // 2.
767
+ findNextEnabledIndex(options, -1, -1, getDisabled); // -1.
768
+ `})}),`
769
+ `,(0,c.jsx)(t.h3,{id:`важные-предусловия`,children:`Важные предусловия`}),`
770
+ `,(0,c.jsxs)(t.ul,{children:[`
771
+ `,(0,c.jsxs)(t.li,{children:[`Передавайте `,(0,c.jsx)(t.code,{children:`currentIndex`}),` в диапазоне `,(0,c.jsx)(t.code,{children:`-1..options.length - 1`}),`.`]}),`
772
+ `,(0,c.jsx)(t.li,{children:`Callback должен уметь работать с каждым элементом списка и не должен менять массив.`}),`
773
+ `,(0,c.jsx)(t.li,{children:`Если текущая опция сама disabled и другого кандидата нет, fallback всё равно может вернуть текущий индекс.`}),`
774
+ `,(0,c.jsxs)(t.li,{children:[`Функции не пропускают `,(0,c.jsx)(t.code,{children:`hidden`}),`, `,(0,c.jsx)(t.code,{children:`aria-disabled`}),` или другие признаки автоматически — это решает callback.`]}),`
775
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`wrap`}),` у `,(0,c.jsx)(t.code,{children:`findNextEnabledIndex`}),` по умолчанию `,(0,c.jsx)(t.code,{children:`false`}),`, а у `,(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`}),` — `,(0,c.jsx)(t.code,{children:`true`}),`.`]}),`
776
+ `]}),`
777
+ `,(0,c.jsx)(t.h2,{id:`createlazycomponent`,children:(0,c.jsx)(t.code,{children:`createLazyComponent`})}),`
778
+ `,(0,c.jsx)(t.h3,{id:`назначение-5`,children:`Назначение`}),`
779
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`createLazyComponent`}),` создаёт `,(0,c.jsx)(t.code,{children:`React.lazy`}),` component для именованного export и кеширует созданную lazy-обёртку.`]}),`
780
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`import { Suspense } from "react";
781
+ import { createLazyComponent } from "@ryuzaki13/react-foundation-lib/utils";
782
+
783
+ type ProfileCardProps = {
784
+ userId: string;
785
+ };
786
+
787
+ const LazyProfileCard = createLazyComponent<ProfileCardProps>(() => import("./ProfileCard"), "ProfileCard", "profile-card");
788
+
789
+ export function ProfilePage() {
790
+ return (
791
+ <Suspense fallback={<p>Загрузка профиля…</p>}>
792
+ <LazyProfileCard userId="U-1" />
793
+ </Suspense>
794
+ );
795
+ }
796
+ `})}),`
797
+ `,(0,c.jsx)(t.p,{children:`Ожидаемый модуль:`}),`
798
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`export function ProfileCard({ userId }: ProfileCardProps) {
799
+ return <article>Пользователь {userId}</article>;
800
+ }
801
+ `})}),`
802
+ `,(0,c.jsx)(t.h3,{id:`когда-начинается-загрузка`,children:`Когда начинается загрузка`}),`
803
+ `,(0,c.jsxs)(t.p,{children:[`Вызов `,(0,c.jsx)(t.code,{children:`createLazyComponent(...)`}),` не вызывает dynamic import. Importer запускается при первом React-рендере lazy component.`]}),`
804
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`создание LazyProfileCard
805
+
806
+ │ importer ещё не вызван
807
+
808
+ первый render <LazyProfileCard />
809
+
810
+
811
+ import("./ProfileCard")
812
+
813
+ ├─ pending ──► ближайший Suspense fallback
814
+
815
+ ├─ fulfilled ─► component render
816
+
817
+ └─ rejected ──► ближайший Error Boundary
818
+ `})}),`
819
+ `,(0,c.jsxs)(t.p,{children:[`Оборачивайте использование в `,(0,c.jsx)(t.code,{children:`<Suspense>`}),`. Для ошибок сети, отсутствующего chunk или неверного export предусмотрите Error Boundary на подходящем уровне приложения.`]}),`
820
+ `,(0,c.jsx)(t.h3,{id:`поиск-export`,children:`Поиск export`}),`
821
+ `,(0,c.jsxs)(t.p,{children:[`Параметр `,(0,c.jsx)(t.code,{children:`componentName`}),` — имя свойства module object. Алгоритм:`]}),`
822
+ `,(0,c.jsxs)(t.ol,{children:[`
823
+ `,(0,c.jsxs)(t.li,{children:[`Если `,(0,c.jsx)(t.code,{children:`module[componentName]`}),` существует, выбирается оно.`]}),`
824
+ `,(0,c.jsxs)(t.li,{children:[`Иначе выбирается `,(0,c.jsx)(t.code,{children:`module.default`}),`.`]}),`
825
+ `,(0,c.jsxs)(t.li,{children:[`Если default нет, выбирается первое значение `,(0,c.jsx)(t.code,{children:`Object.values(module)`}),`.`]}),`
826
+ `,(0,c.jsx)(t.li,{children:`Если модуль отсутствует или выбранное значение не является функцией, lazy render завершается ошибкой.`}),`
827
+ `]}),`
828
+ `,(0,c.jsxs)(t.p,{children:[`Это fallback-поведение означает, что опечатка в `,(0,c.jsx)(t.code,{children:`componentName`}),` не всегда обнаружится: функция может молча выбрать default или первый export. Передавайте точное имя и покрывайте lazy boundary тестом.`]}),`
829
+ `,(0,c.jsxs)(t.p,{children:[`React-компонент должен быть function/class component. Export, созданный как объект `,(0,c.jsx)(t.code,{children:`memo(...)`}),` или `,(0,c.jsx)(t.code,{children:`forwardRef(...)`}),`, может не пройти runtime-проверку `,(0,c.jsx)(t.code,{children:`typeof component === "function"`}),` и не является гарантированно поддержанным значением этого helper.`]}),`
830
+ `,(0,c.jsx)(t.h3,{id:`кеш-по-importer`,children:`Кеш по importer`}),`
831
+ `,(0,c.jsxs)(t.p,{children:[`Без `,(0,c.jsx)(t.code,{children:`cacheKey`}),` результат кешируется по идентичности функции-importer и `,(0,c.jsx)(t.code,{children:`componentName`}),`:`]}),`
832
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const importProfile = () => import("./ProfileCard");
833
+
834
+ const first = createLazyComponent(importProfile, "ProfileCard");
835
+ const second = createLazyComponent(importProfile, "ProfileCard");
836
+
837
+ console.log(first === second); // true.
838
+ `})}),`
839
+ `,(0,c.jsx)(t.p,{children:`Две синтаксически одинаковые, но отдельно созданные arrow-функции имеют разные ссылки:`}),`
840
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const first = createLazyComponent(() => import("./ProfileCard"), "ProfileCard");
841
+ const second = createLazyComponent(() => import("./ProfileCard"), "ProfileCard");
842
+
843
+ console.log(first === second); // false.
844
+ `})}),`
845
+ `,(0,c.jsx)(t.p,{children:`Обычно объявляйте lazy component на уровне модуля, а не внутри React render.`}),`
846
+ `,(0,c.jsxs)(t.h3,{id:`глобальный-строковый-cachekey`,children:[`Глобальный строковый `,(0,c.jsx)(t.code,{children:`cacheKey`})]}),`
847
+ `,(0,c.jsxs)(t.p,{children:[`Третий аргумент создаёт ключ `,(0,c.jsx)(t.code,{children:"${cacheKey}:${componentName}"}),`. Он позволяет разным importer-функциям получить одну lazy-обёртку:`]}),`
848
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`createLazyComponent(firstImporter, "ProfileCard", "profile");
849
+ createLazyComponent(secondImporter, "ProfileCard", "profile");
850
+ `})}),`
851
+ `,(0,c.jsxs)(t.p,{children:[`Второй вызов вернёт ранее созданный результат и фактически будет использовать importer первого вызова. Поэтому `,(0,c.jsx)(t.code,{children:`cacheKey`}),` должен быть глобально уникальным и стабильным. Коллизия может загрузить не тот модуль или создать несоответствие TypeScript props и runtime-компонента.`]}),`
852
+ `,(0,c.jsx)(t.p,{children:`Публичного API для очистки module-level cache нет.`}),`
853
+ `,(0,c.jsx)(t.h3,{id:`ошибки`,children:`Ошибки`}),`
854
+ `,(0,c.jsx)(t.p,{children:`Возможные сообщения helper:`}),`
855
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-text`,children:`Component not found or invalid in module: ProfileCard
856
+ Could not lazy-load component "ProfileCard"
857
+ `})}),`
858
+ `,(0,c.jsxs)(t.p,{children:[`Ошибка возникает во время lazy render, а не обязательно в момент вызова `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),`.`]}),`
859
+ `,(0,c.jsx)(t.h2,{id:`childrencount`,children:(0,c.jsx)(t.code,{children:`childrenCount`})}),`
860
+ `,(0,c.jsx)(t.h3,{id:`назначение-6`,children:`Назначение`}),`
861
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`childrenCount`}),` считает React children как плоский список и рекурсивно раскрывает только React fragments.`]}),`
862
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`import { Fragment } from "react";
863
+ import { childrenCount } from "@ryuzaki13/react-foundation-lib/utils";
864
+
865
+ const count = childrenCount(
866
+ <>
867
+ <span>Первый</span>
868
+ <Fragment>
869
+ <span>Второй</span>
870
+ <span>Третий</span>
871
+ </Fragment>
872
+ {null}
873
+ </>
874
+ );
875
+
876
+ console.log(count); // 3.
877
+ `})}),`
878
+ `,(0,c.jsx)(t.h3,{id:`что-именно-считается`,children:`Что именно считается`}),`
879
+ `,(0,c.jsxs)(t.ul,{children:[`
880
+ `,(0,c.jsxs)(t.li,{children:[`Массивы children обрабатываются стандартным `,(0,c.jsx)(t.code,{children:`React.Children.toArray`}),`.`]}),`
881
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`null`}),`, `,(0,c.jsx)(t.code,{children:`undefined`}),` и boolean placeholders не добавляют видимого child в полученный массив.`]}),`
882
+ `,(0,c.jsx)(t.li,{children:`Fragment не считается отдельным child: функция рекурсивно считает его содержимое.`}),`
883
+ `,(0,c.jsxs)(t.li,{children:[`Обычный React element считается как `,(0,c.jsx)(t.code,{children:`1`}),` независимо от количества его внутренних descendants.`]}),`
884
+ `,(0,c.jsx)(t.li,{children:`Строковый/числовой React child считается как один элемент.`}),`
885
+ `]}),`
886
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`childrenCount(
887
+ <section>
888
+ <span>A</span>
889
+ <span>B</span>
890
+ </section>
891
+ );
892
+ // 1: section — один переданный child; его DOM-потомки не раскрываются.
893
+ `})}),`
894
+ `,(0,c.jsx)(t.p,{children:`Функция не рендерит дерево, не обращается к DOM и может использоваться при SSR.`}),`
895
+ `,(0,c.jsxs)(t.h2,{id:`deepcopynodes-и-deepcopytree`,children:[(0,c.jsx)(t.code,{children:`deepCopyNodes`}),` и `,(0,c.jsx)(t.code,{children:`deepCopyTree`})]}),`
896
+ `,(0,c.jsx)(t.p,{children:`Эти функции копируют структуру дерева: создают новые objects-узлы и новые arrays дочерних узлов. Другие произвольные вложенные поля копируются поверхностно.`}),`
897
+ `,(0,c.jsx)(t.h3,{id:`deepcopynodes`,children:(0,c.jsx)(t.code,{children:`deepCopyNodes`})}),`
898
+ `,(0,c.jsxs)(t.p,{children:[`Используйте для дерева с фиксированным полем `,(0,c.jsx)(t.code,{children:`children`}),`:`]}),`
899
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const metadata = { color: "blue" };
900
+ const source = [
901
+ {
902
+ id: "root",
903
+ metadata,
904
+ children: [{ id: "child", metadata }]
905
+ }
906
+ ];
907
+
908
+ const copy = deepCopyNodes(source);
909
+
910
+ console.log(copy !== source); // true.
911
+ console.log(copy[0] !== source[0]); // true.
912
+ console.log(copy[0].children !== source[0].children); // true.
913
+ console.log(copy[0].metadata === source[0].metadata); // true: поле shallow.
914
+ `})}),`
915
+ `,(0,c.jsx)(t.h3,{id:`deepcopytree`,children:(0,c.jsx)(t.code,{children:`deepCopyTree`})}),`
916
+ `,(0,c.jsx)(t.p,{children:`Используйте, если поле дочерних узлов называется иначе:`}),`
917
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type MenuNode = {
918
+ id: string;
919
+ items?: MenuNode[];
920
+ };
921
+
922
+ const source: MenuNode[] = [{ id: "root", items: [{ id: "child" }] }];
923
+
924
+ const copy = deepCopyTree(source, "items");
925
+
926
+ console.log(copy[0].items !== source[0].items); // true.
927
+ `})}),`
928
+ `,(0,c.jsx)(t.p,{children:`Если значение выбранного поля не является массивом, оно не обходится рекурсивно и остаётся частью поверхностной копии.`}),`
929
+ `,(0,c.jsx)(t.h3,{id:`ограничения-tree-copy`,children:`Ограничения tree copy`}),`
930
+ `,(0,c.jsxs)(t.ul,{children:[`
931
+ `,(0,c.jsx)(t.li,{children:`Входной массив не изменяется.`}),`
932
+ `,(0,c.jsx)(t.li,{children:`Все посещённые nodes и child arrays получают новые ссылки.`}),`
933
+ `,(0,c.jsxs)(t.li,{children:[`Остальные nested objects, functions, `,(0,c.jsx)(t.code,{children:`Date`}),`, `,(0,c.jsx)(t.code,{children:`Map`}),` и т. п. сохраняют исходные ссылки.`]}),`
934
+ `,(0,c.jsx)(t.li,{children:`Циклическое дерево не поддерживается и приведёт к бесконечной рекурсии/ошибке стека.`}),`
935
+ `,(0,c.jsx)(t.li,{children:`Если один и тот же node встречается в двух ветвях, он будет скопирован дважды; identity sharing не сохраняется.`}),`
936
+ `,(0,c.jsxs)(t.li,{children:[`Функции не проверяют уникальность `,(0,c.jsx)(t.code,{children:`id`}),`, корректность parent-child связей или максимальную глубину.`]}),`
937
+ `]}),`
938
+ `,(0,c.jsxs)(t.p,{children:[`Для полного data-only clone всей конфигурации используйте `,(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),`. Для построения таблицы-дерева из `,(0,c.jsx)(t.code,{children:`id`}),`/`,(0,c.jsx)(t.code,{children:`parentId`}),` используйте `,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/tree-table`}),`.`]}),`
939
+ `,(0,c.jsx)(t.h2,{id:`logerror`,children:(0,c.jsx)(t.code,{children:`logError`})}),`
940
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`logError`}),` передаёт все аргументы в `,(0,c.jsx)(t.code,{children:`globalThis.console.error`}),`:`]}),`
941
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { logError } from "@ryuzaki13/react-foundation-lib/utils";
942
+
943
+ try {
944
+ await saveReport();
945
+ } catch (error) {
946
+ logError("Не удалось сохранить отчёт", error);
947
+ }
948
+ `})}),`
949
+ `,(0,c.jsx)(t.p,{children:`Сигнатура:`}),`
950
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`function logError(...args: unknown[]): void;
951
+ `})}),`
952
+ `,(0,c.jsx)(t.p,{children:`Функция:`}),`
953
+ `,(0,c.jsxs)(t.ul,{children:[`
954
+ `,(0,c.jsx)(t.li,{children:`ничего не возвращает;`}),`
955
+ `,(0,c.jsx)(t.li,{children:`не форматирует аргументы;`}),`
956
+ `,(0,c.jsx)(t.li,{children:`не скрывает персональные данные и секреты;`}),`
957
+ `,(0,c.jsxs)(t.li,{children:[`не преобразует `,(0,c.jsx)(t.code,{children:`unknown`}),` в безопасный report;`]}),`
958
+ `,(0,c.jsx)(t.li,{children:`не отправляет ошибку на сервер;`}),`
959
+ `,(0,c.jsx)(t.li,{children:`не подавляет исключения;`}),`
960
+ `,(0,c.jsx)(t.li,{children:`не выполняет retry.`}),`
961
+ `]}),`
962
+ `,(0,c.jsxs)(t.p,{children:[`Не логируйте access tokens, passwords, cookies, полные персональные payloads и другие секреты. Для централизованного сбора и sanitization используйте `,(0,c.jsx)(t.code,{children:`error-report`}),` и его transport.`]}),`
963
+ `,(0,c.jsx)(t.h2,{id:`ssr-browser-и-react-границы`,children:`SSR, browser и React-границы`}),`
964
+ `,(0,c.jsx)(t.h3,{id:`безопасно-на-сервере`,children:`Безопасно на сервере`}),`
965
+ `,(0,c.jsxs)(t.p,{children:[`Следующие функции не читают `,(0,c.jsx)(t.code,{children:`window`}),` или DOM:`]}),`
966
+ `,(0,c.jsxs)(t.ul,{children:[`
967
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`cn`}),`;`]}),`
968
+ `,(0,c.jsx)(t.li,{children:`обе clone-функции;`}),`
969
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`stableStringify`}),`;`]}),`
970
+ `,(0,c.jsx)(t.li,{children:`keyboard и select navigation;`}),`
971
+ `,(0,c.jsx)(t.li,{children:`tree copy;`}),`
972
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`childrenCount`}),`;`]}),`
973
+ `,(0,c.jsx)(t.li,{children:`создание lazy component;`}),`
974
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`logError`}),`, если runtime предоставляет console.`]}),`
975
+ `]}),`
976
+ `,(0,c.jsx)(t.h3,{id:`требуют-globals`,children:`Требуют globals`}),`
977
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`toBase64`}),` требует `,(0,c.jsx)(t.code,{children:`TextEncoder`}),` и `,(0,c.jsx)(t.code,{children:`btoa`}),`, `,(0,c.jsx)(t.code,{children:`encodeBase64`}),` — `,(0,c.jsx)(t.code,{children:`btoa`}),`. Не вызывайте их без проверки в старом/нестандартном server runtime.`]}),`
978
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const canEncode = typeof TextEncoder !== "undefined" && typeof btoa === "function";
979
+ `})}),`
980
+ `,(0,c.jsx)(t.h3,{id:`reactlazy-и-ssr`,children:`React.lazy и SSR`}),`
981
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`createLazyComponent`}),` не обращается к DOM, однако дальнейшее поведение зависит от React renderer/framework. Suspense и загрузку chunk на сервере настраивает host framework. Не предполагавайте, что обычный browser dynamic import автоматически настроит streaming SSR или preload.`]}),`
982
+ `,(0,c.jsx)(t.h2,{id:`производительность`,children:`Производительность`}),`
983
+ `,(0,c.jsx)(t.h3,{id:`clone-функции`,children:`Clone-функции`}),`
984
+ `,(0,c.jsxs)(t.p,{children:[`Обе функции обходят весь поддерживаемый graph, то есть время и дополнительная память примерно линейны относительно количества посещённых элементов и свойств: `,(0,c.jsx)(t.code,{children:`O(n)`}),`.`]}),`
985
+ `,(0,c.jsx)(t.p,{children:`Не клонируйте большой state на каждом React render. Клонирование обычно выполняют:`}),`
986
+ `,(0,c.jsxs)(t.ul,{children:[`
987
+ `,(0,c.jsx)(t.li,{children:`при создании initial draft;`}),`
988
+ `,(0,c.jsx)(t.li,{children:`при обработке явного изменения;`}),`
989
+ `,(0,c.jsx)(t.li,{children:`при формировании save snapshot;`}),`
990
+ `,(0,c.jsx)(t.li,{children:`на границе восстановления конфигурации.`}),`
991
+ `]}),`
992
+ `,(0,c.jsx)(t.h3,{id:`stablestringify-1`,children:(0,c.jsx)(t.code,{children:`stableStringify`})}),`
993
+ `,(0,c.jsxs)(t.p,{children:[`Объекты дополнительно сортируют ключи. Для объекта с `,(0,c.jsx)(t.code,{children:`k`}),` ключами сортировка стоит примерно `,(0,c.jsx)(t.code,{children:`O(k log k)`}),`. Не сериализуйте большой payload на каждом render без memoization.`]}),`
994
+ `,(0,c.jsx)(t.h3,{id:`navigation-и-tree-helpers`,children:`Navigation и tree helpers`}),`
995
+ `,(0,c.jsxs)(t.ul,{children:[`
996
+ `,(0,c.jsxs)(t.li,{children:[`First/last/next navigation в худшем случае просматривает `,(0,c.jsx)(t.code,{children:`O(n)`}),` опций.`]}),`
997
+ `,(0,c.jsx)(t.li,{children:`Tree copy посещает каждый node один раз, но глубокое дерево может исчерпать call stack.`}),`
998
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`childrenCount`}),` посещает переданные React children и fragments.`]}),`
999
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`cn`}),` линейно проходит аргументы и ключи conditional objects.`]}),`
1000
+ `]}),`
1001
+ `,(0,c.jsx)(t.h3,{id:`lazy-cache`,children:`Lazy cache`}),`
1002
+ `,(0,c.jsxs)(t.p,{children:[`Кеш `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),` живёт на уровне загруженного модуля библиотеки. Строковые `,(0,c.jsx)(t.code,{children:`cacheKey`}),` удерживаются до выгрузки module runtime; не создавайте бесконечное количество динамических ключей из user input.`]}),`
1003
+ `,(0,c.jsx)(t.h2,{id:`тестирование-consumer-кода`,children:`Тестирование consumer-кода`}),`
1004
+ `,(0,c.jsx)(t.h3,{id:`cn`,children:(0,c.jsx)(t.code,{children:`cn`})}),`
1005
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { expect, it } from "vitest";
1006
+ import { cn } from "@ryuzaki13/react-foundation-lib/utils";
1007
+
1008
+ it("добавляет active-класс", () => {
1009
+ expect(cn("button", { active: true, disabled: false })).toBe("button active");
1010
+ });
1011
+ `})}),`
1012
+ `,(0,c.jsx)(t.h3,{id:`literal-draft-и-clone`,children:`Literal draft и clone`}),`
1013
+ `,(0,c.jsx)(t.p,{children:`Проверяйте отдельно неизменность пользовательского draft и форму save snapshot:`}),`
1014
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`it("сохраняет literal draft при клонировании", () => {
1015
+ const draft = {
1016
+ title: "Новая группа ",
1017
+ visible: false,
1018
+ tags: ["A", "A", ""]
1019
+ };
1020
+
1021
+ const copy = deepCopyWithoutFunctions(draft);
1022
+
1023
+ expect(copy).toEqual(draft);
1024
+ expect(copy).not.toBe(draft);
1025
+ expect(copy.tags).not.toBe(draft.tags);
1026
+ });
1027
+ `})}),`
1028
+ `,(0,c.jsx)(t.p,{children:`Для cycles проверяйте связь с clone, а не только deep equality:`}),`
1029
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`expect(copy.self).toBe(copy);
1030
+ `})}),`
1031
+ `,(0,c.jsx)(t.h3,{id:`keyboard`,children:`Keyboard`}),`
1032
+ `,(0,c.jsxs)(t.p,{children:[`Проверяйте три результата: return value, `,(0,c.jsx)(t.code,{children:`preventDefault`}),` и действие.`]}),`
1033
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const preventDefault = vi.fn();
1034
+ const action = vi.fn();
1035
+
1036
+ expect(handleKeyboardActivation({ key: "Enter", preventDefault }, action)).toBe(true);
1037
+ expect(preventDefault).toHaveBeenCalledOnce();
1038
+ expect(action).toHaveBeenCalledOnce();
1039
+ `})}),`
1040
+ `,(0,c.jsxs)(t.p,{children:[`Отдельно проверьте `,(0,c.jsx)(t.code,{children:`disabled`}),` и необрабатываемую клавишу.`]}),`
1041
+ `,(0,c.jsx)(t.h3,{id:`lazy-component`,children:`Lazy component`}),`
1042
+ `,(0,c.jsxs)(t.p,{children:[`Используйте DOM-окружение теста, `,(0,c.jsx)(t.code,{children:`<Suspense>`}),` и дождитесь разрешения Promise. Проверяйте:`]}),`
1043
+ `,(0,c.jsxs)(t.ul,{children:[`
1044
+ `,(0,c.jsx)(t.li,{children:`видимость fallback во время ожидания, если это важно для UX;`}),`
1045
+ `,(0,c.jsx)(t.li,{children:`успешный named export;`}),`
1046
+ `,(0,c.jsx)(t.li,{children:`ошибку загрузки через Error Boundary;`}),`
1047
+ `,(0,c.jsx)(t.li,{children:`props загруженного компонента;`}),`
1048
+ `,(0,c.jsx)(t.li,{children:`отсутствие повторной загрузки при повторном render.`}),`
1049
+ `]}),`
1050
+ `,(0,c.jsxs)(t.p,{children:[`Не делайте тест зависимым от кеша, оставленного другим тестом: используйте уникальные importer-функции и уникальные `,(0,c.jsx)(t.code,{children:`cacheKey`}),`.`]}),`
1051
+ `,(0,c.jsx)(t.h3,{id:`base64`,children:`Base64`}),`
1052
+ `,(0,c.jsx)(t.p,{children:`Сравнивайте результат после UTF-8 decode, особенно для кириллицы и emoji:`}),`
1053
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`expect(decodeBase64(toBase64("Привет 👋"))).toBe("Привет 👋");
1054
+ `})}),`
1055
+ `,(0,c.jsx)(t.h2,{id:`полный-api-справочник`,children:`Полный API-справочник`}),`
1056
+ `,(0,c.jsx)(t.h3,{id:`runtime-exports`,children:`Runtime exports`}),`
1057
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Export`}),(0,c.jsx)(t.th,{children:`Параметры`}),(0,c.jsx)(t.th,{children:`Результат`}),(0,c.jsx)(t.th,{children:`Side effect / особенность`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`cn`})}),(0,c.jsx)(t.td,{children:`строки, boolean/nullish и conditional objects`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`string`})}),(0,c.jsx)(t.td,{children:`нет`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`classNames`})}),(0,c.jsxs)(t.td,{children:[`как у `,(0,c.jsx)(t.code,{children:`cn`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`string`})}),(0,c.jsxs)(t.td,{children:[`deprecated-алиас `,(0,c.jsx)(t.code,{children:`cn`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})}),(0,c.jsxs)(t.td,{children:[`значение, `,(0,c.jsx)(t.code,{children:`{ arrayFunctionStrategy? }`})]}),(0,c.jsx)(t.td,{children:`строгая глубокая копия`}),(0,c.jsxs)(t.td,{children:[`unsupported object бросает `,(0,c.jsx)(t.code,{children:`TypeError`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})}),(0,c.jsxs)(t.td,{children:[`значение, `,(0,c.jsx)(t.code,{children:`{ arrayFunctionStrategy?, preservePrototype? }`})]}),(0,c.jsx)(t.td,{children:`расширенная глубокая копия`}),(0,c.jsx)(t.td,{children:`неподдержанные built-ins не гарантируются`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`stableStringify`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`unknown`})}),(0,c.jsx)(t.td,{children:`JSON string`}),(0,c.jsxs)(t.td,{children:[`может вызвать `,(0,c.jsx)(t.code,{children:`toJSON`}),`/getter или бросить JSON-ошибку`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`toBase64`})}),(0,c.jsx)(t.td,{children:`строка`}),(0,c.jsx)(t.td,{children:`Base64 string`}),(0,c.jsxs)(t.td,{children:[`использует `,(0,c.jsx)(t.code,{children:`TextEncoder`}),` и `,(0,c.jsx)(t.code,{children:`btoa`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`encodeBase64`})}),(0,c.jsx)(t.td,{children:`строка`}),(0,c.jsx)(t.td,{children:`Base64 string`}),(0,c.jsxs)(t.td,{children:[`использует `,(0,c.jsx)(t.code,{children:`encodeURIComponent`}),` и `,(0,c.jsx)(t.code,{children:`btoa`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`keyboardActivationKeys`})}),(0,c.jsx)(t.td,{children:`—`}),(0,c.jsxs)(t.td,{children:[`readonly `,(0,c.jsx)(t.code,{children:`["Enter", " "]`})]}),(0,c.jsx)(t.td,{children:`module constant`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`isKeyboardActivationKey`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`key: string`})}),(0,c.jsx)(t.td,{children:`type-guard boolean`}),(0,c.jsx)(t.td,{children:`нет`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`handleKeyboardActivation`})}),(0,c.jsxs)(t.td,{children:[`event-like, action, `,(0,c.jsx)(t.code,{children:`{ disabled? }`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`boolean`})}),(0,c.jsxs)(t.td,{children:[`вызывает `,(0,c.jsx)(t.code,{children:`preventDefault`}),` и action при обработке`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`RovingFocusTargetOptions`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`number | null`})}),(0,c.jsx)(t.td,{children:`только вычисляет индекс`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`findFirstEnabledIndex`})}),(0,c.jsx)(t.td,{children:`options, optional disabled callback`}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`number`}),`, `,(0,c.jsx)(t.code,{children:`-1`}),` если нет`]}),(0,c.jsx)(t.td,{children:`нет`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`findLastEnabledIndex`})}),(0,c.jsx)(t.td,{children:`options, optional disabled callback`}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`number`}),`, `,(0,c.jsx)(t.code,{children:`-1`}),` если нет`]}),(0,c.jsx)(t.td,{children:`нет`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`findNextEnabledIndex`})}),(0,c.jsxs)(t.td,{children:[`options, current index, `,(0,c.jsx)(t.code,{children:`1 | -1`}),`, callback, `,(0,c.jsx)(t.code,{children:`{ wrap? }`})]}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`number`}),`, иногда `,(0,c.jsx)(t.code,{children:`-1`})]}),(0,c.jsx)(t.td,{children:`нет`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`createLazyComponent`})}),(0,c.jsx)(t.td,{children:`importer, component name, optional cache key`}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`LazyExoticComponent`})}),(0,c.jsx)(t.td,{children:`кеш; import при первом render`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`childrenCount`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ReactNode`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`number`})}),(0,c.jsx)(t.td,{children:`fragments раскрываются`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyNodes`})}),(0,c.jsxs)(t.td,{children:[`дерево с `,(0,c.jsx)(t.code,{children:`children`})]}),(0,c.jsx)(t.td,{children:`новое дерево`}),(0,c.jsx)(t.td,{children:`произвольные nested fields shallow`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyTree`})}),(0,c.jsx)(t.td,{children:`дерево, optional children field`}),(0,c.jsx)(t.td,{children:`новое дерево`}),(0,c.jsx)(t.td,{children:`произвольные nested fields shallow`})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`logError`})}),(0,c.jsxs)(t.td,{children:[`любое количество `,(0,c.jsx)(t.code,{children:`unknown`})]}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`void`})}),(0,c.jsxs)(t.td,{children:[`вызывает `,(0,c.jsx)(t.code,{children:`globalThis.console.error`})]})]})]})]}),`
1058
+ `,(0,c.jsx)(t.h3,{id:`публичные-типы`,children:`Публичные типы`}),`
1059
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`Тип`}),(0,c.jsx)(t.th,{children:`Значение`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`ToggleClassName`})}),(0,c.jsxs)(t.td,{children:[(0,c.jsx)(t.code,{children:`Record<string, boolean | undefined>`}),` для conditional classes`]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`PureClassName`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`string | boolean | undefined | null`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`KeyboardActivationKey`})}),(0,c.jsxs)(t.td,{children:[`union `,(0,c.jsx)(t.code,{children:`"Enter" | " "`})]})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`RovingFocusTargetOptions`})}),(0,c.jsx)(t.td,{children:`current index, count, key, orientation и optional wrap`})]})]})]}),`
1060
+ `,(0,c.jsx)(t.h3,{id:`значения-по-умолчанию`,children:`Значения по умолчанию`}),`
1061
+ `,(0,c.jsxs)(t.table,{children:[(0,c.jsx)(t.thead,{children:(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.th,{children:`API`}),(0,c.jsx)(t.th,{children:`Опция`}),(0,c.jsx)(t.th,{children:`Default`})]})}),(0,c.jsxs)(t.tbody,{children:[(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`arrayFunctionStrategy`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`"omit"`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`arrayFunctionStrategy`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`"undefined"`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCloneWithoutFunctions`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`preservePrototype`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`false`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`handleKeyboardActivation`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`disabled`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`false`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`wrap`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`true`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`findNextEnabledIndex`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`wrap`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`false`})})]}),(0,c.jsxs)(t.tr,{children:[(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`deepCopyTree`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`childrenField`})}),(0,c.jsx)(t.td,{children:(0,c.jsx)(t.code,{children:`"children"`})})]})]})]}),`
1062
+ `,(0,c.jsx)(t.h2,{id:`типичные-ошибки`,children:`Типичные ошибки`}),`
1063
+ `,(0,c.jsx)(t.h3,{id:`импорт-из-корня-пакета`,children:`Импорт из корня пакета`}),`
1064
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`// Неверно.
1065
+ import { cn } from "@ryuzaki13/react-foundation-lib";
1066
+
1067
+ // Верно.
1068
+ import { cn } from "@ryuzaki13/react-foundation-lib/utils";
1069
+ `})}),`
1070
+ `,(0,c.jsx)(t.h3,{id:`ожидание-одинакового-default-clone-массива`,children:`Ожидание одинакового default clone массива`}),`
1071
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`deepCopyWithoutFunctions([1, () => 2, 3]);
1072
+ // [1, 3]
1073
+
1074
+ deepCloneWithoutFunctions([1, () => 2, 3]);
1075
+ // [1, undefined, 3]
1076
+ `})}),`
1077
+ `,(0,c.jsx)(t.p,{children:`Всегда выбирайте функцию по контракту данных, а не по похожему названию.`}),`
1078
+ `,(0,c.jsx)(t.h3,{id:`использование-clone-как-normalize`,children:`Использование clone как normalize`}),`
1079
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const copy = deepCopyWithoutFunctions(draft);
1080
+
1081
+ // Ошибочное ожидание: clone не делает trim, dedupe и defaults.
1082
+ `})}),`
1083
+ `,(0,c.jsx)(t.p,{children:`Нормализация должна быть отдельной операцией на явно названной boundary.`}),`
1084
+ `,(0,c.jsx)(t.h3,{id:`передача-класса-в-строгий-config-clone`,children:`Передача класса в строгий config clone`}),`
1085
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`deepCopyWithoutFunctions(new URL("https://example.com"));
1086
+ // TypeError.
1087
+ `})}),`
1088
+ `,(0,c.jsx)(t.p,{children:`Сначала преобразуйте значение в поддерживаемую data-only форму.`}),`
1089
+ `,(0,c.jsx)(t.h3,{id:`ожидание-глубокого-clone-от-tree-helpers`,children:`Ожидание глубокого clone от tree helpers`}),`
1090
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const copy = deepCopyNodes(source);
1091
+ copy[0].metadata.value = 2;
1092
+ // Если metadata — произвольный object, исходный metadata тоже изменится.
1093
+ `})}),`
1094
+ `,(0,c.jsx)(t.p,{children:`Tree helpers копируют структуру узлов, а не всё содержимое каждого поля.`}),`
1095
+ `,(0,c.jsx)(t.h3,{id:`использование-base64-как-защиты`,children:`Использование Base64 как защиты`}),`
1096
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`const visibleToAnyone = toBase64(accessToken);
1097
+ `})}),`
1098
+ `,(0,c.jsx)(t.p,{children:`Base64 легко декодируется. Не храните секрет только потому, что строка стала нечитаемой визуально.`}),`
1099
+ `,(0,c.jsxs)(t.h3,{id:`cn-с-массивом`,children:[(0,c.jsx)(t.code,{children:`cn`}),` с массивом`]}),`
1100
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`cn(["button", "active"] as never); // Пустая строка.
1101
+ `})}),`
1102
+ `,(0,c.jsx)(t.p,{children:`Передавайте строки отдельными аргументами или conditional object.`}),`
1103
+ `,(0,c.jsxs)(t.h3,{id:`кастомная-keyboard-активация-на-button`,children:[`Кастомная keyboard-активация на `,(0,c.jsx)(t.code,{children:`<button>`})]}),`
1104
+ `,(0,c.jsx)(t.p,{children:`Нативная кнопка уже умеет Enter/Space. Дополнительный handler может вызвать действие дважды.`}),`
1105
+ `,(0,c.jsx)(t.h3,{id:`lazy-component-внутри-render`,children:`Lazy component внутри render`}),`
1106
+ `,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-tsx`,children:`function Page() {
1107
+ const LazyCard = createLazyComponent(() => import("./Card"), "Card");
1108
+ return <LazyCard />;
1109
+ }
1110
+ `})}),`
1111
+ `,(0,c.jsxs)(t.p,{children:[`Importer-функция создаётся заново при каждом render, поэтому WeakMap cache не помогает. Объявляйте `,(0,c.jsx)(t.code,{children:`LazyCard`}),` на уровне модуля.`]}),`
1112
+ `,(0,c.jsxs)(t.h3,{id:`коллизия-cachekey`,children:[`Коллизия `,(0,c.jsx)(t.code,{children:`cacheKey`})]}),`
1113
+ `,(0,c.jsxs)(t.p,{children:[`Один `,(0,c.jsx)(t.code,{children:`cacheKey + componentName`}),` для разных модулей возвращает первый закешированный компонент. Включайте в ключ стабильное имя модуля/сценария.`]}),`
1114
+ `,(0,c.jsxs)(t.h3,{id:`stablestringify-для-map-cycles-или-bigint`,children:[(0,c.jsx)(t.code,{children:`stableStringify`}),` для `,(0,c.jsx)(t.code,{children:`Map`}),`, cycles или `,(0,c.jsx)(t.code,{children:`bigint`})]}),`
1115
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`Map`}),` обычно превращается в `,(0,c.jsx)(t.code,{children:`{}`}),`, cycle и `,(0,c.jsx)(t.code,{children:`bigint`}),` выбрасывают ошибку. Сначала создайте явное JSON-compatible representation.`]}),`
1116
+ `,(0,c.jsxs)(t.h3,{id:`путаница-null-и--1`,children:[`Путаница `,(0,c.jsx)(t.code,{children:`null`}),` и `,(0,c.jsx)(t.code,{children:`-1`})]}),`
1117
+ `,(0,c.jsxs)(t.ul,{children:[`
1118
+ `,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`}),` возвращает `,(0,c.jsx)(t.code,{children:`null`}),`, если клавиша не относится к navigation или элементов нет.`]}),`
1119
+ `,(0,c.jsxs)(t.li,{children:[`Select-navigation helpers возвращают `,(0,c.jsx)(t.code,{children:`-1`}),`, если подходящего индекса нет.`]}),`
1120
+ `]}),`
1121
+ `,(0,c.jsx)(t.p,{children:`Проверяйте именно тот sentinel, который заявлен функцией.`}),`
1122
+ `,(0,c.jsx)(t.h2,{id:`вопросы-и-ответы`,children:`Вопросы и ответы`}),`
1123
+ `,(0,c.jsxs)(t.h3,{id:`можно-ли-импортировать-только-cn-не-устанавливая-react`,children:[`Можно ли импортировать только `,(0,c.jsx)(t.code,{children:`cn`}),`, не устанавливая React?`]}),`
1124
+ `,(0,c.jsxs)(t.p,{children:[`Entrypoint `,(0,c.jsx)(t.code,{children:`/utils`}),` публично реэкспортирует также React-зависимые modules. Для надёжного ESM resolution host должен предоставить совместимый React peer, даже если конкретный bundler затем tree-shake неиспользуемый код.`]}),`
1125
+ `,(0,c.jsx)(t.h3,{id:`какая-clone-функция-подходит-для-zustand-draftconfig`,children:`Какая clone-функция подходит для Zustand draft/config?`}),`
1126
+ `,(0,c.jsxs)(t.p,{children:[`Обычно `,(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),`: она принимает только предсказуемую data-only структуру и явно ошибается на специальных объектах. Она клонирует буквально и не нормализует draft.`]}),`
1127
+ `,(0,c.jsxs)(t.h3,{id:`почему-не-structuredclone`,children:[`Почему не `,(0,c.jsx)(t.code,{children:`structuredClone`}),`?`]}),`
1128
+ `,(0,c.jsxs)(t.p,{children:[`Эти функции имеют отдельный контракт удаления функций и контролируемое поведение массивов. `,(0,c.jsx)(t.code,{children:`deepCopyWithoutFunctions`}),` дополнительно запрещает неподходящие для config объекты. `,(0,c.jsx)(t.code,{children:`structuredClone`}),` решает другую общую задачу и имеет другой набор поддерживаемых/ошибочных значений.`]}),`
1129
+ `,(0,c.jsxs)(t.h3,{id:`можно-ли-клонировать-dom-node-file-или-blob`,children:[`Можно ли клонировать DOM node, `,(0,c.jsx)(t.code,{children:`File`}),` или `,(0,c.jsx)(t.code,{children:`Blob`}),`?`]}),`
1130
+ `,(0,c.jsx)(t.p,{children:`Нет, это не поддерживаемый контракт clone-функций модуля. Используйте API соответствующего типа или храните в конфигурации только serializable metadata/reference.`}),`
1131
+ `,(0,c.jsx)(t.h3,{id:`удаляет-ли-clone-дубликаты-и-пробелы`,children:`Удаляет ли clone дубликаты и пробелы?`}),`
1132
+ `,(0,c.jsx)(t.p,{children:`Нет. Clone сохраняет literal data. Для canonical save snapshot нужна отдельная normalize-функция на границе сохранения.`}),`
1133
+ `,(0,c.jsxs)(t.h3,{id:`можно-ли-сравнить-любые-два-объекта-через-stablestringify`,children:[`Можно ли сравнить любые два объекта через `,(0,c.jsx)(t.code,{children:`stableStringify`}),`?`]}),`
1134
+ `,(0,c.jsxs)(t.p,{children:[`Нет. Подходят небольшие JSON-compatible data structures без cycles, functions, symbols, `,(0,c.jsx)(t.code,{children:`bigint`}),`, getters с эффектами и специальных collections. JSON-семантика может скрыть различия.`]}),`
1135
+ `,(0,c.jsxs)(t.h3,{id:`stablestringify-создаёт-hash`,children:[(0,c.jsx)(t.code,{children:`stableStringify`}),` создаёт hash?`]}),`
1136
+ `,(0,c.jsxs)(t.p,{children:[`Нет, результат содержит весь JSON-текст. Для hash/id используйте публичный модуль `,(0,c.jsx)(t.code,{children:`crypto`}),`, учитывая назначение конкретной hash-функции.`]}),`
1137
+ `,(0,c.jsx)(t.h3,{id:`как-сделать-base64url`,children:`Как сделать Base64URL?`}),`
1138
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`toBase64`}),` и `,(0,c.jsx)(t.code,{children:`encodeBase64`}),` возвращают стандартный Base64. Если protocol требует Base64URL, следуйте его точным правилам замены `,(0,c.jsx)(t.code,{children:`+`}),`/`,(0,c.jsx)(t.code,{children:`/`}),`, удаления/сохранения padding и декодирования. Не называйте ad hoc-преобразование криптографической защитой.`]}),`
1139
+ `,(0,c.jsxs)(t.h3,{id:`почему-handlekeyboardactivation-не-вызывает-click`,children:[`Почему `,(0,c.jsx)(t.code,{children:`handleKeyboardActivation`}),` не вызывает click?`]}),`
1140
+ `,(0,c.jsxs)(t.p,{children:[`Helper принимает явный `,(0,c.jsx)(t.code,{children:`action`}),`, чтобы не зависеть от DOM. Host сам решает, какое действие соответствует активации и какие `,(0,c.jsx)(t.code,{children:`role`}),`, ARIA и focus rules нужны control.`]}),`
1141
+ `,(0,c.jsx)(t.h3,{id:`чем-roving-focus-отличается-от-select-navigation`,children:`Чем roving focus отличается от select navigation?`}),`
1142
+ `,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`getRovingFocusTargetIndex`}),` знает orientation, Arrow/Home/End и границы, но не знает disabled items. Select-navigation helpers знают disabled items и направление `,(0,c.jsx)(t.code,{children:`1/-1`}),`, но не интерпретируют `,(0,c.jsx)(t.code,{children:`KeyboardEvent.key`}),` и не перемещают DOM-фокус.`]}),`
1143
+ `,(0,c.jsxs)(t.h3,{id:`нужно-ли-передавать-cachekey-в-createlazycomponent`,children:[`Нужно ли передавать `,(0,c.jsx)(t.code,{children:`cacheKey`}),` в `,(0,c.jsx)(t.code,{children:`createLazyComponent`}),`?`]}),`
1144
+ `,(0,c.jsx)(t.p,{children:`Нет. Стабильной importer-функции и component name достаточно. Строковый ключ нужен только когда разные importer references намеренно должны делить один lazy component; его уникальность становится ответственностью host.`}),`
1145
+ `,(0,c.jsxs)(t.h3,{id:`childrencount-считает-dom-элементы-после-рендера`,children:[(0,c.jsx)(t.code,{children:`childrenCount`}),` считает DOM-элементы после рендера?`]}),`
1146
+ `,(0,c.jsx)(t.p,{children:`Нет. Функция считает переданную React-структуру до DOM и раскрывает fragments. Один обычный component/element считается одним child, даже если позже отрендерит много DOM nodes.`})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};