@ryuzaki13/react-foundation-ui 1.4.2 → 1.4.3

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 (505) hide show
  1. package/dist/advanced-search/index.js +12 -11
  2. package/dist/advanced-search/index.js.map +1 -1
  3. package/dist/badge/index.js +1 -1
  4. package/dist/base-table/index.js +2 -2
  5. package/dist/button/index.js +1 -1
  6. package/dist/chunks/{CalendarView-KCkhCtK-.js → CalendarView-Z_XWk7aI.js} +8 -8
  7. package/dist/chunks/{CalendarView-KCkhCtK-.js.map → CalendarView-Z_XWk7aI.js.map} +1 -1
  8. package/dist/chunks/{ImageViewerRuntime-RN49by8Y.js → ImageViewerRuntime-BMs3BBkV.js} +4 -4
  9. package/dist/chunks/{ImageViewerRuntime-RN49by8Y.js.map → ImageViewerRuntime-BMs3BBkV.js.map} +1 -1
  10. package/dist/chunks/{TextEditorLexicalClient-CVTrglWP.js → TextEditorLexicalClient-CK8j3RA4.js} +16 -18
  11. package/dist/chunks/{TextEditorLexicalClient-CVTrglWP.js.map → TextEditorLexicalClient-CK8j3RA4.js.map} +1 -1
  12. package/dist/chunks/{badge-Cri0-kVK.js → badge-DwIUjH0a.js} +2 -2
  13. package/dist/chunks/{badge-Cri0-kVK.js.map → badge-DwIUjH0a.js.map} +1 -1
  14. package/dist/chunks/{base-table-D5IqsjQD.js → base-table-BFsVwXg3.js} +13 -12
  15. package/dist/chunks/{base-table-D5IqsjQD.js.map → base-table-BFsVwXg3.js.map} +1 -1
  16. package/dist/chunks/{button-CC0Jdx1j.js → button-BU2kRzwu.js} +2 -2
  17. package/dist/chunks/{button-CC0Jdx1j.js.map → button-BU2kRzwu.js.map} +1 -1
  18. package/dist/chunks/check-box-Dd3YFuxd.js.map +1 -1
  19. package/dist/chunks/{context-menu-DQeR3y7M.js → context-menu-C6RO7soI.js} +7 -2
  20. package/dist/chunks/{context-menu-DQeR3y7M.js.map → context-menu-C6RO7soI.js.map} +1 -1
  21. package/dist/chunks/{date-input-DBJisPRz.js → date-input-BzExUQnc.js} +5 -5
  22. package/dist/chunks/{date-input-DBJisPRz.js.map → date-input-BzExUQnc.js.map} +1 -1
  23. package/dist/chunks/{flex-DYZ0IbU6.js → flex-C7njxZ74.js} +10 -7
  24. package/dist/chunks/{flex-DYZ0IbU6.js.map → flex-C7njxZ74.js.map} +1 -1
  25. package/dist/chunks/floating-arrow-BE-z4QkE.js.map +1 -1
  26. package/dist/chunks/{input-BCJfUdK_.js → input-Bp6_Ucgr.js} +15 -15
  27. package/dist/chunks/{input-BCJfUdK_.js.map → input-Bp6_Ucgr.js.map} +1 -1
  28. package/dist/chunks/{input-files-Dcc5K-_1.js → input-files-D1JzSw_Y.js} +2 -2
  29. package/dist/chunks/{input-files-Dcc5K-_1.js.map → input-files-D1JzSw_Y.js.map} +1 -1
  30. package/dist/chunks/{input-search-B7HmrAM7.js → input-search-Bkhcinru.js} +2 -2
  31. package/dist/chunks/{input-search-B7HmrAM7.js.map → input-search-Bkhcinru.js.map} +1 -1
  32. package/dist/chunks/{misc-DIF5h9ba.js → misc-BYxxlJz6.js} +3 -3
  33. package/dist/chunks/{misc-DIF5h9ba.js.map → misc-BYxxlJz6.js.map} +1 -1
  34. package/dist/chunks/{modal-DXHX_sA-.js → modal-paexEF0j.js} +4 -5
  35. package/dist/chunks/{modal-DXHX_sA-.js.map → modal-paexEF0j.js.map} +1 -1
  36. package/dist/chunks/{multi-select-CWx12rgb.js → multi-select-COa6-owj.js} +3 -3
  37. package/dist/chunks/{multi-select-CWx12rgb.js.map → multi-select-COa6-owj.js.map} +1 -1
  38. package/dist/chunks/{picker-BAQ9NeHe.js → picker-e6IsrMUG.js} +3 -3
  39. package/dist/chunks/{picker-BAQ9NeHe.js.map → picker-e6IsrMUG.js.map} +1 -1
  40. package/dist/chunks/{popover-xJJqy1v6.js → popover-CGU3MlsH.js} +14 -14
  41. package/dist/chunks/{popover-xJJqy1v6.js.map → popover-CGU3MlsH.js.map} +1 -1
  42. package/dist/chunks/radio-group-CM9Lg_nc.js.map +1 -1
  43. package/dist/chunks/{select-BPb-eL3O.js → select-C95db02j.js} +32 -31
  44. package/dist/chunks/{select-BPb-eL3O.js.map → select-C95db02j.js.map} +1 -1
  45. package/dist/chunks/sortable-DcTIAbjD.js.map +1 -1
  46. package/dist/chunks/{table-xMAjqtcY.js → table-Dd5BcC0k.js} +3 -3
  47. package/dist/chunks/{table-xMAjqtcY.js.map → table-Dd5BcC0k.js.map} +1 -1
  48. package/dist/chunks/{table-column-interactions-BGd5Lwy9.js → table-column-interactions-DzEvVuXe.js} +8 -5
  49. package/dist/chunks/{table-column-interactions-BGd5Lwy9.js.map → table-column-interactions-DzEvVuXe.js.map} +1 -1
  50. package/dist/chunks/useODataSelectBase-CKe1AVMI.js.map +1 -1
  51. package/dist/chunks/wheel-picker-FS58cRsQ.js.map +1 -1
  52. package/dist/context-menu/index.js +1 -1
  53. package/dist/date-input/index.js +2 -2
  54. package/dist/date-time-input/index.js +4 -4
  55. package/dist/date-time-input/index.js.map +1 -1
  56. package/dist/detail/index.js.map +1 -1
  57. package/dist/dialog/index.js.map +1 -1
  58. package/dist/disclosure/index.js +1 -1
  59. package/dist/disclosure/index.js.map +1 -1
  60. package/dist/drop-zone/index.js +1 -1
  61. package/dist/drop-zone/index.js.map +1 -1
  62. package/dist/errors/index.js +1 -1
  63. package/dist/errors/index.js.map +1 -1
  64. package/dist/expandable-action-panel/index.js +2 -2
  65. package/dist/expandable-action-panel/index.js.map +1 -1
  66. package/dist/flex/index.js +1 -1
  67. package/dist/fullscreen-portal/index.js +3 -3
  68. package/dist/fullscreen-portal/index.js.map +1 -1
  69. package/dist/image/index.js +5 -5
  70. package/dist/image/index.js.map +1 -1
  71. package/dist/input/index.js +1 -1
  72. package/dist/input-date-time/index.js +1 -1
  73. package/dist/input-date-time/index.js.map +1 -1
  74. package/dist/input-file/index.js +1 -1
  75. package/dist/input-file/index.js.map +1 -1
  76. package/dist/input-files/index.js +1 -1
  77. package/dist/input-image/index.js +1 -1
  78. package/dist/input-image/index.js.map +1 -1
  79. package/dist/input-search/index.js +1 -1
  80. package/dist/layout-picker/index.js +3 -3
  81. package/dist/layout-picker/index.js.map +1 -1
  82. package/dist/list/index.js +7 -7
  83. package/dist/list/index.js.map +1 -1
  84. package/dist/listbox/index.js.map +1 -1
  85. package/dist/misc/index.js +1 -1
  86. package/dist/modal/index.js +1 -1
  87. package/dist/multi-select/index.js +1 -1
  88. package/dist/notifications/index.js +13 -11
  89. package/dist/notifications/index.js.map +1 -1
  90. package/dist/pages/index.js.map +1 -1
  91. package/dist/panel/index.js.map +1 -1
  92. package/dist/picker/index.js +1 -1
  93. package/dist/popover/index.js +1 -1
  94. package/dist/preset-range-date-input/index.js +2 -2
  95. package/dist/preset-range-date-input/index.js.map +1 -1
  96. package/dist/preset-select/index.js +1 -1
  97. package/dist/radio-button/index.js.map +1 -1
  98. package/dist/select/index.js +1 -1
  99. package/dist/simple-table/index.js +1 -1
  100. package/dist/slider/index.js +27 -24
  101. package/dist/slider/index.js.map +1 -1
  102. package/dist/splitter/index.js.map +1 -1
  103. package/dist/state-select/index.js +12 -10
  104. package/dist/state-select/index.js.map +1 -1
  105. package/dist/switch/index.js +1 -1
  106. package/dist/switch/index.js.map +1 -1
  107. package/dist/table/index.js +1 -1
  108. package/dist/table-column-interactions/index.js +1 -1
  109. package/dist/table-sorting/index.js +1 -1
  110. package/dist/table-sorting/index.js.map +1 -1
  111. package/dist/tabs/index.js +6 -6
  112. package/dist/tabs/index.js.map +1 -1
  113. package/dist/tag-input/index.js +1 -1
  114. package/dist/tag-input/index.js.map +1 -1
  115. package/dist/text/index.js +10 -8
  116. package/dist/text/index.js.map +1 -1
  117. package/dist/text-editor/index.js +2 -2
  118. package/dist/textarea/index.js +1 -1
  119. package/dist/textarea/index.js.map +1 -1
  120. package/dist/toggle/index.js.map +1 -1
  121. package/dist/toolbar/index.js +1 -2
  122. package/dist/toolbar/index.js.map +1 -1
  123. package/dist/tree/index.js.map +1 -1
  124. package/dist/tree-select/index.js +83 -80
  125. package/dist/tree-select/index.js.map +1 -1
  126. package/dist/tree-table/index.js +2 -2
  127. package/dist/tree-table/index.js.map +1 -1
  128. package/package.json +51 -59
  129. package/storybook-static/assets/{Badge-SZ48u9qp.js → Badge-DHexWW92.js} +11 -11
  130. package/storybook-static/assets/Badge.stories-CeWDekpP.js +54 -0
  131. package/storybook-static/assets/Button-VdPdxcvG.js +12 -0
  132. package/storybook-static/assets/{Button-CFCpYiPy.js → Button-kybsFNS9.js} +10 -10
  133. package/storybook-static/assets/Button.stories-DhgYDM_q.js +75 -0
  134. package/storybook-static/assets/{DateInput-BfFTwd_P.css → CalendarView-DKvrkS40.css} +1 -1
  135. package/storybook-static/assets/CalendarView-DTX0eO8t.js +1 -0
  136. package/storybook-static/assets/CheckBox-B6rTemHK.js +2 -0
  137. package/storybook-static/assets/{CheckBox-FoMSruZC.js → CheckBox-CDwboiFD.js} +11 -11
  138. package/storybook-static/assets/CheckBox.module-BBzuj5He.js +1 -0
  139. package/storybook-static/assets/CheckBox.stories-BSMihxpY.js +60 -0
  140. package/storybook-static/assets/Color-6AOWCN3U-D5F38IUU.js +1 -0
  141. package/storybook-static/assets/{ContextMenu-CU_1kOzV.js → ContextMenu-2ZQAeo_p.js} +9 -9
  142. package/storybook-static/assets/ContextMenu-CQtvL8kx.js +1 -0
  143. package/storybook-static/assets/ContextMenu.stories-Dtz2YIGk.js +90 -0
  144. package/storybook-static/assets/{DateInput-BeZ5esVE.js → DateInput-D41aWZ7_.js} +11 -11
  145. package/storybook-static/assets/DateInput-DBwgBhFj.js +1 -0
  146. package/storybook-static/assets/DateInput-pmGiwdvw.css +1 -0
  147. package/storybook-static/assets/{DateInput.stories-Bkw2r8CD.js → DateInput.stories-CMV96t-8.js} +2 -2
  148. package/storybook-static/assets/{DateRangePresetSelect-C_mLvEoK.js → DateRangePresetSelect-BLKJkg8X.js} +8 -8
  149. package/storybook-static/assets/DateRangePresetSelect-DXYYFJJn.js +3 -0
  150. package/storybook-static/assets/DateRangePresetSelect.stories-BNtFx_iG.js +11 -0
  151. package/storybook-static/assets/{Detail-WzciiK9S.js → Detail-BHcGLZok.js} +11 -11
  152. package/storybook-static/assets/Detail.stories-C4smn8Uu.js +44 -0
  153. package/storybook-static/assets/{Dialog-CwLsVxJY.js → Dialog-kji1ho-G.js} +9 -9
  154. package/storybook-static/assets/Dialog.stories-DYzrVcIT.js +31 -0
  155. package/storybook-static/assets/{Disclosure-BlRuGrk2.js → Disclosure-BVLfp53o.js} +10 -10
  156. package/storybook-static/assets/Disclosure.stories-DcV1pGCt.js +41 -0
  157. package/storybook-static/assets/DocsRenderer-JROSPFPF-CCwX0YiR.js +2 -0
  158. package/storybook-static/assets/{DropZone-Cr3nfCWA.js → DropZone-6iWHt6C_.js} +10 -10
  159. package/storybook-static/assets/DropZone.stories-bASZNbD5.js +44 -0
  160. package/storybook-static/assets/ExpandableActionPanel.stories-CMMbHs_d.js +20 -0
  161. package/storybook-static/assets/{Flex-C10912WS.js → Flex-BJViOwhH.js} +18 -18
  162. package/storybook-static/assets/Flex.stories-CI6DdxU7.js +300 -0
  163. package/storybook-static/assets/FlexContainer-LmZIdhq2.js +1 -0
  164. package/storybook-static/assets/FlexItem-vkDYa5tA.js +3 -0
  165. package/storybook-static/assets/FloatingPopover-CPLOruAY.js +1 -0
  166. package/storybook-static/assets/FloatingPopover-DC84VrV3.css +1 -0
  167. package/storybook-static/assets/FormattedTableCell-CV4yLuxl.js +18 -0
  168. package/storybook-static/assets/FormattedTableCell-CY3E21k8.css +1 -0
  169. package/storybook-static/assets/Grid-BCzygAqy.js +52 -0
  170. package/storybook-static/assets/{Grid-G88y3oB_.js → Grid-CNEn2bRE.js} +18 -18
  171. package/storybook-static/assets/{Grid.stories-BV7zL-6n.js → Grid.stories-qFo5E3qE.js} +2 -2
  172. package/storybook-static/assets/{Grid-Bb0gH6CX.js → GridContainer-qDguE1HS.js} +2 -53
  173. package/storybook-static/assets/ImageCropper.stories-BeQI7oKQ.js +115 -0
  174. package/storybook-static/assets/ImageRenderer-DK2ibQyr.js +2 -0
  175. package/storybook-static/assets/ImageRenderer.stories-C1T4ne0G.js +22 -0
  176. package/storybook-static/assets/ImageView.stories-D_Q-ZBtQ.js +9 -0
  177. package/storybook-static/assets/{ImageViewer.stories-PlFXSB5n.js → ImageViewer.stories-boombTJI.js} +5 -5
  178. package/storybook-static/assets/ImageViewerRuntime-D8KSESgf.js +51 -0
  179. package/storybook-static/assets/{Input-pyUNDVtk.js → Input-CGHba0oM.js} +11 -11
  180. package/storybook-static/assets/Input-DtOsW7ur.js +3 -0
  181. package/storybook-static/assets/Input.stories-C0qWd6SH.js +38 -0
  182. package/storybook-static/assets/{InputDateTime-CWk5KBwD.js → InputDateTime-CgYkmVYu.js} +11 -11
  183. package/storybook-static/assets/InputDateTime.stories-Brxo7Chn.js +35 -0
  184. package/storybook-static/assets/{InputFile-BLQq7mY9.js → InputFile-Bsxafe88.js} +10 -10
  185. package/storybook-static/assets/InputFile.stories-BzEV7ybE.js +36 -0
  186. package/storybook-static/assets/{InputFiles-B6J4XBdP.js → InputFiles-KJFUsmSS.js} +10 -10
  187. package/storybook-static/assets/InputFiles.stories-ffjxiHSh.js +33 -0
  188. package/storybook-static/assets/InputFilesList-D6B5g99M.js +1 -0
  189. package/storybook-static/assets/{InputImage--2PSB_E_.js → InputImage-Cd39V4Vc.js} +10 -10
  190. package/storybook-static/assets/InputImage.stories-n-tpY8OO.js +51 -0
  191. package/storybook-static/assets/{LayoutPicker-RZDisgZ_.js → LayoutPicker-CGQFfQk6.js} +13 -13
  192. package/storybook-static/assets/LayoutPicker.stories-xSL2qafC.js +449 -0
  193. package/storybook-static/assets/{Listbox-xwfNjBpV.js → Listbox-CxISK8c5.js} +10 -10
  194. package/storybook-static/assets/Listbox.stories-BdQBmVFI.js +47 -0
  195. package/storybook-static/assets/{Modal-HJt_Y-a6.js → Modal-BiaAWMdV.js} +12 -12
  196. package/storybook-static/assets/Modal.stories-GV7fGqyd.js +180 -0
  197. package/storybook-static/assets/MultiSelect-D5XFosSU.js +2 -0
  198. package/storybook-static/assets/{MultiSelect-CvNsFdE4.js → MultiSelect-Df2CpyNH.js} +11 -11
  199. package/storybook-static/assets/MultiSelect.stories-BEVQF6hO.js +29 -0
  200. package/storybook-static/assets/MultiSelectToken-CrVawISu.js +1 -0
  201. package/storybook-static/assets/NoData-C7KqaHUh.css +1 -0
  202. package/storybook-static/assets/NoData-Fm23iF4n.js +1 -0
  203. package/storybook-static/assets/{NotificationsHost-DXCf3CQX.js → NotificationsHost-C2vSwAjz.js} +9 -9
  204. package/storybook-static/assets/NotificationsHost.stories-IbgayDlM.js +25 -0
  205. package/storybook-static/assets/{ODataMultiSelect-CIJNiwGb.js → ODataMultiSelect-oW3kW0nO.js} +15 -15
  206. package/storybook-static/assets/ODataMultiSelect.stories-CP6_jGSr.js +73 -0
  207. package/storybook-static/assets/{ODataSelect-BDga9TUb.js → ODataSelect-CrGF8fyC.js} +15 -15
  208. package/storybook-static/assets/ODataSelect.stories-DTv31Rkv.js +73 -0
  209. package/storybook-static/assets/ODataTreeMultiSelect-D0h8H3gw.js +19 -0
  210. package/storybook-static/assets/ODataTreeMultiSelect.stories-CM8QjG8r.js +30 -0
  211. package/storybook-static/assets/ODataTreeSelect-PWn0-hI4.js +17 -0
  212. package/storybook-static/assets/ODataTreeSelect.stories-2UkFTnbE.js +24 -0
  213. package/storybook-static/assets/OneStepScroller-CH6K7wiO.js +5 -0
  214. package/storybook-static/assets/OneStepScroller-NRYd-egY.css +1 -0
  215. package/storybook-static/assets/{PeriodSelect-BJbjl62O.js → PeriodSelect-BtwJuAO6.js} +13 -13
  216. package/storybook-static/assets/PeriodSelect.stories-BH8I5Wmg.js +64 -0
  217. package/storybook-static/assets/PickerSelectionToolbar-BcL8-O6n.js +2 -0
  218. package/storybook-static/assets/PickerTriggerActions-C8Asdp5e.js +1 -0
  219. package/storybook-static/assets/{Popover-Dg2T0DoN.js → Popover-Ch5btFhR.js} +11 -11
  220. package/storybook-static/assets/Popover-DGX7JNNK.css +1 -0
  221. package/storybook-static/assets/Popover-Djns7yXR.js +2 -0
  222. package/storybook-static/assets/Popover.stories-Bask2I1I.js +69 -0
  223. package/storybook-static/assets/{PresetRangeDateInput-CNmTMNHF.js → PresetRangeDateInput-DvsTjQNP.js} +8 -8
  224. package/storybook-static/assets/PresetRangeDateInput.stories-BNfOUWgp.js +15 -0
  225. package/storybook-static/assets/PresetSelect-9zitP0-V.js +5 -0
  226. package/storybook-static/assets/{RadioButton-2rfUPkwC.js → RadioButton-Yb9bQKYe.js} +10 -10
  227. package/storybook-static/assets/RadioButton.stories-FIFxXFVP.js +36 -0
  228. package/storybook-static/assets/RadioGroup-CWsVqwtm.js +1 -0
  229. package/storybook-static/assets/{RadioGroup-BduGGVKj.js → RadioGroup-Dn0zL838.js} +10 -10
  230. package/storybook-static/assets/RadioGroup.stories-B_drop9x.js +42 -0
  231. package/storybook-static/assets/Scrollable-3Z6b5g0Z.js +1 -0
  232. package/storybook-static/assets/{Select-DnZ83aZs.js → Select-BaR8D89E.js} +13 -13
  233. package/storybook-static/assets/Select-BiOxxy0y.js +12 -0
  234. package/storybook-static/assets/Select.stories-CMlWu7vC.js +46 -0
  235. package/storybook-static/assets/SelectOptionContent-DhtCMwz6.js +1 -0
  236. package/storybook-static/assets/{SerializableSelect-BiFhAxAJ.js → SerializableSelect-BDiZo_-M.js} +12 -12
  237. package/storybook-static/assets/SerializableSelect.stories-DgC6oiRx.js +46 -0
  238. package/storybook-static/assets/{SingleDateTimeInput-Bc-ifbML.js → SingleDateTimeInput-Dx1fvzyr.js} +12 -12
  239. package/storybook-static/assets/SingleDateTimeInput.stories-NRUE7nnA.js +78 -0
  240. package/storybook-static/assets/Slider-DJpzPo7f.js +1 -0
  241. package/storybook-static/assets/{Slider-DfjBSsR3.js → Slider-aiFcrSGY.js} +15 -15
  242. package/storybook-static/assets/Slider.stories-B0YHmFf5.js +77 -0
  243. package/storybook-static/assets/{SliderInput-o9uCcVMP.js → SliderInput-sOoxvdku.js} +16 -16
  244. package/storybook-static/assets/SliderInput.stories-BYk1V19Z.js +68 -0
  245. package/storybook-static/assets/{Sortable-B6Y9Q9Yn.js → Sortable-CuVT40f8.js} +13 -13
  246. package/storybook-static/assets/Sortable.stories-KSWGoKrN.js +141 -0
  247. package/storybook-static/assets/{Splitter-CfUVnAs7.js → Splitter-EoNOj4XF.js} +11 -11
  248. package/storybook-static/assets/Splitter.stories-CuAZab2y.js +22 -0
  249. package/storybook-static/assets/{StateSelect-h0i4M4vO.js → StateSelect-B_M50HZl.js} +10 -10
  250. package/storybook-static/assets/StateSelect.stories-DQ_MzvL4.js +47 -0
  251. package/storybook-static/assets/StringToggle.stories-BbRysCKA.js +6 -0
  252. package/storybook-static/assets/{Switch-CPKaENqL.js → Switch-DO_tyZIc.js} +10 -10
  253. package/storybook-static/assets/Switch.stories-BQakMoPp.js +26 -0
  254. package/storybook-static/assets/{Table-xV66crR1.js → Table-CVK5rwmT.js} +22 -22
  255. package/storybook-static/assets/Table.stories-IZaleOjp.js +122 -0
  256. package/storybook-static/assets/{Tabs-v9YZeJoc.js → Tabs-DAaWUQb4.js} +15 -15
  257. package/storybook-static/assets/Tabs.stories-BC8LwG22.js +58 -0
  258. package/storybook-static/assets/TagInput.stories-CrXD57LV.js +18 -0
  259. package/storybook-static/assets/Text-cVBcGheg.js +1 -0
  260. package/storybook-static/assets/{Textarea-CRThqX0z.js → Textarea-9VdIC6G0.js} +10 -10
  261. package/storybook-static/assets/Textarea.stories-CEaMwEau.js +27 -0
  262. package/storybook-static/assets/TimePanel-vx1aOwT4.js +1 -0
  263. package/storybook-static/assets/TimePanel.stories-BKyiLEgy.js +25 -0
  264. package/storybook-static/assets/Toggle-CyajrRVE.js +1 -0
  265. package/storybook-static/assets/{Toggle-CzopviU2.js → Toggle-DrNoVpGe.js} +10 -10
  266. package/storybook-static/assets/Toggle.stories-CT0mQbdm.js +30 -0
  267. package/storybook-static/assets/TreeMultiSelect-CtDZ1cXU.js +1 -0
  268. package/storybook-static/assets/TreeMultiSelect-ag5i_Hw_.js +19 -0
  269. package/storybook-static/assets/TreeMultiSelect.stories-BxrbKopS.js +35 -0
  270. package/storybook-static/assets/TreePickerBase-DQzUtuAm.js +22 -0
  271. package/storybook-static/assets/TreeSelect-BNuJBo9x.js +1 -0
  272. package/storybook-static/assets/TreeSelect-CL8REXC5.js +16 -0
  273. package/storybook-static/assets/TreeSelect.stories-CsWGc9X0.js +18 -0
  274. package/storybook-static/assets/{TreeTable-DbzoCcR5.js → TreeTable-DrIFC4Oh.js} +22 -22
  275. package/storybook-static/assets/TreeTable.stories-Dq5c4_qe.js +83 -0
  276. package/storybook-static/assets/WithTooltip-7X4HQR7L-Cakt_JaX.js +9 -0
  277. package/storybook-static/assets/array-BBSjoTRy-CIRmlF93.js +1 -0
  278. package/storybook-static/assets/{async-D27PcxoG.js → async-0-Te_uje.js} +3 -3
  279. package/storybook-static/assets/axe-Bq-2xuso.js +20 -0
  280. package/storybook-static/assets/blocks-Dz3dJBcm.js +48 -0
  281. package/storybook-static/assets/browserAndReact-kZBm3nQe.js +105 -0
  282. package/storybook-static/assets/check-BMyoSD8F.js +1 -0
  283. package/storybook-static/assets/chevron-down-QDFtnGcg.js +1 -0
  284. package/storybook-static/assets/chevron-left-BoVuWD4h.js +1 -0
  285. package/storybook-static/assets/chevron-right-DS62_o_9.js +1 -0
  286. package/storybook-static/assets/chunk-242VQQM5-BMWWiybC.js +1 -0
  287. package/storybook-static/assets/chunk-DRQKCCAG-CqE-Zrl9.js +1 -0
  288. package/storybook-static/assets/chunk-IMSF75WX-yvVUwIQZ.js +6 -0
  289. package/storybook-static/assets/chunk-KJHJLCBK-D-yQfkOi.js +1 -0
  290. package/storybook-static/assets/chunk-QQBDHPVZ-B98qboss.js +1 -0
  291. package/storybook-static/assets/chunk-W22LQPXL-DDIvKskF.js +18 -0
  292. package/storybook-static/assets/circle-alert-CXg50Gb0.js +1 -0
  293. package/storybook-static/assets/circle-check-BPfYNWmz.js +1 -0
  294. package/storybook-static/assets/components-BejapTpU.js +241 -0
  295. package/storybook-static/assets/contextMenu-DtXkMNr6.js +2 -0
  296. package/storybook-static/assets/date-segments-D3HouZ37.js +1 -0
  297. package/storybook-static/assets/dom-B3G_GtJw.js +1 -0
  298. package/storybook-static/assets/download-DnZ6jhvY.js +1 -0
  299. package/storybook-static/assets/error-BZrNlEUO.js +1 -0
  300. package/storybook-static/assets/file-vPGnhPr-.js +1 -0
  301. package/storybook-static/assets/filesAndExcel-CXMXtMjq.js +122 -0
  302. package/storybook-static/assets/floating-ui.react-PN45KvBS.js +1 -0
  303. package/storybook-static/assets/formatter-L2YTDE3Q-x0raBH34.js +1 -0
  304. package/storybook-static/assets/formatters--mhLir82-v41eaI4a.js +1 -0
  305. package/storybook-static/assets/formatters-DGXR8csR.js +291 -0
  306. package/storybook-static/assets/formatters-runtime-GsS-hTg9.js +384 -0
  307. package/storybook-static/assets/foundationLib-XrLbqi3r.js +82 -0
  308. package/storybook-static/assets/hooks-Ddmw7JMF.js +5 -0
  309. package/storybook-static/assets/iframe-CrnMVMTc.js +1151 -0
  310. package/storybook-static/assets/iframe-FUHzX0Mr.js +1 -0
  311. package/storybook-static/assets/info-Dqq5QHG7.js +1 -0
  312. package/storybook-static/assets/{matchers-JIUQ3HVY-BPS-eazD.js → matchers-JIUQ3HVY-DvR2XErZ.js} +3 -3
  313. package/storybook-static/assets/media-BycWpjAl.js +1 -0
  314. package/storybook-static/assets/odata-BaxgzNGj.js +1 -0
  315. package/storybook-static/assets/odata-service-DnPlNGpU-Bpd4Zh9L.js +3 -0
  316. package/storybook-static/assets/odataAndTables-OEVW-gFK.js +126 -0
  317. package/storybook-static/assets/{odataFetchFn-BVgXXKgx.js → odataFetchFn-BLWeF0ZQ.js} +3 -3
  318. package/storybook-static/assets/odataStoryFixtures-BbswaX_5.js +25 -0
  319. package/storybook-static/assets/{persisted-D8qUQbts.js → persisted-BpFojVXw.js} +3 -3
  320. package/storybook-static/assets/preload-helper-BHmFeTtP.js +1 -0
  321. package/storybook-static/assets/pureUtilities-3afQk5ld.js +69 -0
  322. package/storybook-static/assets/react-18-CgkwBzTo.js +9 -0
  323. package/storybook-static/assets/react-C21x__mS.js +1 -0
  324. package/storybook-static/assets/react-CpOcCp9T.js +9 -0
  325. package/storybook-static/assets/react-CvkUhHUq.js +1 -0
  326. package/storybook-static/assets/react-dom-2o2phaJG.js +1 -0
  327. package/storybook-static/assets/react-qN2cStNd.js +1 -0
  328. package/storybook-static/assets/refresh-cw-B2VU4UNA.js +1 -0
  329. package/storybook-static/assets/rolldown-runtime-C0FnF6B9.js +1 -0
  330. package/storybook-static/assets/runtimeAndState-BEFDbOiZ.js +117 -0
  331. package/storybook-static/assets/settings-2-CLJhjWJl.js +1 -0
  332. package/storybook-static/assets/sortable-DW_Veba0.js +1 -0
  333. package/storybook-static/assets/syntaxhighlighter-T5IQBZDB-D0RhvxXU.js +6 -0
  334. package/storybook-static/assets/theming-mTWhffkp.js +39 -0
  335. package/storybook-static/assets/trash-2-yLqdtpz8.js +1 -0
  336. package/storybook-static/assets/treeStoryFixtures-Ci7STpiz.js +1 -0
  337. package/storybook-static/assets/triangle-alert-wI8Cd8tI.js +1 -0
  338. package/storybook-static/assets/ui.module-DoMIk8Oc.js +1 -0
  339. package/storybook-static/assets/uiClasses-CO3Cdv1E.js +1 -0
  340. package/storybook-static/assets/useFlexClasses-Gn9spXEB.js +1 -0
  341. package/storybook-static/assets/useODataSelectBase-WnxdcAM4.js +1 -0
  342. package/storybook-static/assets/useODataTreeData-C7L5TOjl.js +1 -0
  343. package/storybook-static/assets/usePickerDefaultFilter-DdxyE_i8.js +1 -0
  344. package/storybook-static/assets/usePickerQuery-CAWYFpCv.js +1 -0
  345. package/storybook-static/assets/usePickerTriggerController-BRXUlggw.js +1 -0
  346. package/storybook-static/assets/utils-DUM89eIj.js +1 -0
  347. package/storybook-static/assets/x-CyFk00QC.js +1 -0
  348. package/storybook-static/iframe.html +8 -3
  349. package/storybook-static/index.html +6 -0
  350. package/storybook-static/index.json +1 -1
  351. package/storybook-static/project.json +1 -1
  352. package/storybook-static/sb-addons/a11y-3/manager-bundle.js +3 -3
  353. package/storybook-static/sb-addons/chromatic-com-storybook-1/manager-bundle.js +17 -17
  354. package/storybook-static/sb-addons/docs-2/manager-bundle.js +16 -1
  355. package/storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +85 -83
  356. package/storybook-static/sb-addons/vitest-4/manager-bundle.js +1 -1
  357. package/storybook-static/sb-manager/globals-runtime.js +9939 -7695
  358. package/storybook-static/sb-manager/runtime.js +16128 -15326
  359. package/storybook-static/vite-inject-mocker-entry.js +2 -2
  360. package/storybook-static/assets/Badge.stories-CzsgAfG9.js +0 -51
  361. package/storybook-static/assets/Button-MoWVKehO.js +0 -12
  362. package/storybook-static/assets/Button.stories-wwep4c2p.js +0 -75
  363. package/storybook-static/assets/CheckBox-DHvne_6w.js +0 -2
  364. package/storybook-static/assets/CheckBox.module-ezWPE2pa.js +0 -1
  365. package/storybook-static/assets/CheckBox.stories-C14Axs5p.js +0 -60
  366. package/storybook-static/assets/Color-KMSTOMOX-CmMBFN4-.js +0 -1
  367. package/storybook-static/assets/ContextMenu.stories-Dr-tkpqd.js +0 -90
  368. package/storybook-static/assets/DateInput-erobPRG_.js +0 -1
  369. package/storybook-static/assets/DateRangePresetSelect-Cg90Kc_w.js +0 -3
  370. package/storybook-static/assets/DateRangePresetSelect.stories-BVap0joC.js +0 -11
  371. package/storybook-static/assets/Detail.stories-CLdtvJ7q.js +0 -44
  372. package/storybook-static/assets/Dialog.stories-Dx0jZO19.js +0 -31
  373. package/storybook-static/assets/Disclosure.stories-DhUdeDK6.js +0 -41
  374. package/storybook-static/assets/DocsRenderer-JROSPFPF-Dd1n83Uq.js +0 -2
  375. package/storybook-static/assets/DropZone.stories-6yYrwQOe.js +0 -44
  376. package/storybook-static/assets/DropdownMenu-D_2LfViU.js +0 -1
  377. package/storybook-static/assets/ExpandableActionPanel.stories-DVOFSOlm.js +0 -20
  378. package/storybook-static/assets/Flex-V-qg6Ejw.js +0 -3
  379. package/storybook-static/assets/Flex.stories-BZv94LD8.js +0 -300
  380. package/storybook-static/assets/ImageCropper.stories-MLFZyJxZ.js +0 -115
  381. package/storybook-static/assets/ImageRenderer-DHhD7mUz.js +0 -2
  382. package/storybook-static/assets/ImageRenderer.stories-ChcPymk2.js +0 -22
  383. package/storybook-static/assets/ImageView.stories-DszVNgC8.js +0 -9
  384. package/storybook-static/assets/ImageViewerRuntime-D8wFAKx5.js +0 -51
  385. package/storybook-static/assets/Input-BGdz8TmT.js +0 -3
  386. package/storybook-static/assets/Input.stories-Ban0Gnck.js +0 -38
  387. package/storybook-static/assets/InputDateTime.stories-DgKVmf54.js +0 -35
  388. package/storybook-static/assets/InputFile.stories-VnRv_q2r.js +0 -36
  389. package/storybook-static/assets/InputFiles-Dn9afnyd.js +0 -1
  390. package/storybook-static/assets/InputFiles.stories-CLVn5Xfq.js +0 -33
  391. package/storybook-static/assets/InputImage.stories-D__QcSho.js +0 -51
  392. package/storybook-static/assets/LayoutPicker.stories-BCnR-zBu.js +0 -449
  393. package/storybook-static/assets/Listbox.stories-B0HctqVp.js +0 -47
  394. package/storybook-static/assets/Modal.stories-BE-VpK-a.js +0 -180
  395. package/storybook-static/assets/MultiSelect-CaCNRNIe.js +0 -2
  396. package/storybook-static/assets/MultiSelect.stories-CNkbVGsb.js +0 -29
  397. package/storybook-static/assets/NotificationsHost.stories-BgqvZzT3.js +0 -25
  398. package/storybook-static/assets/ODataMultiSelect-CMyI4yYs.js +0 -1
  399. package/storybook-static/assets/ODataMultiSelect.stories-DTGCC6np.js +0 -73
  400. package/storybook-static/assets/ODataSelect-CGplYBh_.js +0 -1
  401. package/storybook-static/assets/ODataSelect.stories-CsxqRAvn.js +0 -73
  402. package/storybook-static/assets/ODataTreeMultiSelect-4ZiAtFZk.js +0 -19
  403. package/storybook-static/assets/ODataTreeMultiSelect.stories-B29Od8BL.js +0 -30
  404. package/storybook-static/assets/ODataTreeSelect-yZy7MBsZ.js +0 -17
  405. package/storybook-static/assets/ODataTreeSelect.stories-H7eaj1Sz.js +0 -24
  406. package/storybook-static/assets/PeriodSelect.stories-6CEzS2_H.js +0 -64
  407. package/storybook-static/assets/Popover.stories-BNgWOHlJ.js +0 -69
  408. package/storybook-static/assets/PresetRangeDateInput.stories-6UPVDF62.js +0 -15
  409. package/storybook-static/assets/RadioButton.stories-DbdFfJqO.js +0 -36
  410. package/storybook-static/assets/RadioGroup-BA21indC.js +0 -1
  411. package/storybook-static/assets/RadioGroup.stories-Ce6x0WUN.js +0 -42
  412. package/storybook-static/assets/Select-DyO25wSA.js +0 -12
  413. package/storybook-static/assets/Select.stories-CQ8f9fY9.js +0 -46
  414. package/storybook-static/assets/SelectOptionContent-fC4HFG5Q.js +0 -1
  415. package/storybook-static/assets/SerializableSelect-ki4BThj7.js +0 -4
  416. package/storybook-static/assets/SerializableSelect.stories-BzXBkWPI.js +0 -43
  417. package/storybook-static/assets/SingleDateTimeInput.stories-CI2yrD-f.js +0 -78
  418. package/storybook-static/assets/Slider.stories-D3O3_tqE.js +0 -77
  419. package/storybook-static/assets/SliderInput.stories-D1puleZB.js +0 -67
  420. package/storybook-static/assets/Sortable.stories-BoaL4W6r.js +0 -141
  421. package/storybook-static/assets/Splitter.stories-DJpFzZVJ.js +0 -22
  422. package/storybook-static/assets/StateSelect.stories-Ch2Gzzmd.js +0 -47
  423. package/storybook-static/assets/StringToggle.stories-B8qIG0M3.js +0 -6
  424. package/storybook-static/assets/Switch.stories-BysIhUHa.js +0 -26
  425. package/storybook-static/assets/Table.stories-CBpgmq7b.js +0 -122
  426. package/storybook-static/assets/Tabs.stories-BPYZuvzR.js +0 -58
  427. package/storybook-static/assets/TagInput.stories-BwOEnVpz.js +0 -18
  428. package/storybook-static/assets/Textarea.stories-BSJGz7JF.js +0 -27
  429. package/storybook-static/assets/TimePanel-ClMfq_py.js +0 -1
  430. package/storybook-static/assets/TimePanel.stories-_FqWdmta.js +0 -25
  431. package/storybook-static/assets/Toggle-BFhzeK2e.js +0 -1
  432. package/storybook-static/assets/Toggle.stories-Dw5UkD_b.js +0 -30
  433. package/storybook-static/assets/TreeMultiSelect-CerqHY2K.js +0 -19
  434. package/storybook-static/assets/TreeMultiSelect-Dw7FI3ic.js +0 -1
  435. package/storybook-static/assets/TreeMultiSelect.stories-BTQKFbeP.js +0 -35
  436. package/storybook-static/assets/TreePickerBase-rJISGJBT.js +0 -22
  437. package/storybook-static/assets/TreeSelect-CQ1vj_c9.js +0 -16
  438. package/storybook-static/assets/TreeSelect-Cp_lX0-B.js +0 -1
  439. package/storybook-static/assets/TreeSelect.stories-D6Q02Phx.js +0 -18
  440. package/storybook-static/assets/TreeTable.stories-YfyhkqH9.js +0 -83
  441. package/storybook-static/assets/WithTooltip-7X4HQR7L-BSQyvCOM.js +0 -9
  442. package/storybook-static/assets/axe-GLfyhAYL.js +0 -20
  443. package/storybook-static/assets/base-table-BNO0lnTL.css +0 -1
  444. package/storybook-static/assets/base-table-Dy3fEhQe.js +0 -18
  445. package/storybook-static/assets/blocks-ixiC6_NZ.js +0 -285
  446. package/storybook-static/assets/button-DZpTIXz2.js +0 -1
  447. package/storybook-static/assets/check-box-DByHwJGx.js +0 -1
  448. package/storybook-static/assets/chunk-242VQQM5-Dtm7LRbQ.js +0 -1
  449. package/storybook-static/assets/chunk-3LY4VQVK-BohfESrT.js +0 -6
  450. package/storybook-static/assets/chunk-LITCR56V-XaMGADKk.js +0 -18
  451. package/storybook-static/assets/contextMenu-BbMrBF3b.js +0 -2
  452. package/storybook-static/assets/date-7kR6zFX5.js +0 -461
  453. package/storybook-static/assets/date-segments-CzU9k5bl.js +0 -1
  454. package/storybook-static/assets/error-BRUjWXbJ.js +0 -1
  455. package/storybook-static/assets/file-CI_sonB1.js +0 -291
  456. package/storybook-static/assets/file-hArYcyES.js +0 -1
  457. package/storybook-static/assets/flex-C--89Z3g.js +0 -1
  458. package/storybook-static/assets/floating-ui.react-DLXcGGFR.js +0 -1
  459. package/storybook-static/assets/formatter-L2YTDE3Q-DgyzUf7M.js +0 -1
  460. package/storybook-static/assets/formatters-BtIOYENB.js +0 -3
  461. package/storybook-static/assets/formulas-DRh9I2eS.js +0 -2
  462. package/storybook-static/assets/grid-DLxeTZJe.js +0 -1
  463. package/storybook-static/assets/hooks-DWeJq8G1.js +0 -5
  464. package/storybook-static/assets/iframe-BJGIOdSH.js +0 -1119
  465. package/storybook-static/assets/input-DXi75xv1.js +0 -1
  466. package/storybook-static/assets/mdx-react-shim-CmoAsjhK.js +0 -1
  467. package/storybook-static/assets/media-DWFaNgLM.js +0 -1
  468. package/storybook-static/assets/misc-BElIqBdV.css +0 -1
  469. package/storybook-static/assets/misc-DNZTbWc6.js +0 -5
  470. package/storybook-static/assets/notifications-DjtgzFqT.js +0 -1
  471. package/storybook-static/assets/number-Xkw1yPJo.js +0 -2
  472. package/storybook-static/assets/odata-C4Liwkjx.js +0 -1
  473. package/storybook-static/assets/odata-service-C2oJ-ZmZ.js +0 -1
  474. package/storybook-static/assets/odataStoryFixtures-eEGvvtmw.js +0 -25
  475. package/storybook-static/assets/picker-DsP4xCcJ.js +0 -2
  476. package/storybook-static/assets/popover-BiQHI7Wi.css +0 -1
  477. package/storybook-static/assets/popover-CuFTypCp.js +0 -2
  478. package/storybook-static/assets/preload-helper-B45gAKPr.js +0 -1
  479. package/storybook-static/assets/preset-select-SPNHA-mp.js +0 -5
  480. package/storybook-static/assets/pwa-B7uYfAPd.js +0 -640
  481. package/storybook-static/assets/queryClient-CA0puYc0.js +0 -567
  482. package/storybook-static/assets/react-18-CaNSmcD-.js +0 -9
  483. package/storybook-static/assets/react-3qMIUlAf.js +0 -9
  484. package/storybook-static/assets/react-dom-BC7xZNHy.js +0 -1
  485. package/storybook-static/assets/select-sUla5-3b.js +0 -1
  486. package/storybook-static/assets/slider--Yp_sa_W.js +0 -2
  487. package/storybook-static/assets/sortable-jALaQqYE.js +0 -1
  488. package/storybook-static/assets/syntaxhighlighter-RTCFPKCB-u_WDwfDn.js +0 -6
  489. package/storybook-static/assets/text-D5xgciF8.js +0 -4
  490. package/storybook-static/assets/theming-oB64gsjY.js +0 -39
  491. package/storybook-static/assets/treeStoryFixtures-Y_nnjz0_.js +0 -1
  492. package/storybook-static/assets/ui-DWDaBPQx.js +0 -1
  493. package/storybook-static/assets/ui.module-wFHXkJzp.js +0 -1
  494. package/storybook-static/assets/uiClasses-CaHp0EWd.js +0 -1
  495. package/storybook-static/assets/useODataSelectBase-DjlPxmxr.js +0 -1
  496. package/storybook-static/assets/useODataTreeData-1W6cbuec.js +0 -1
  497. package/storybook-static/assets/utils-DzbSigQl.js +0 -1
  498. package/storybook-static/assets/valueState-GnkKWBTr.js +0 -277
  499. /package/storybook-static/assets/{DropdownMenu-BgzIzwzM.css → ContextMenu-BgzIzwzM.css} +0 -0
  500. /package/storybook-static/assets/{Grid-K9R_IHaw.css → GridContainer-K9R_IHaw.css} +0 -0
  501. /package/storybook-static/assets/{InputFiles-ByK52qUe.css → InputFilesList-ByK52qUe.css} +0 -0
  502. /package/storybook-static/assets/{MultiSelect-BoIwmje6.css → MultiSelectToken-BoIwmje6.css} +0 -0
  503. /package/storybook-static/assets/{slider-DMDFRH6B.css → Slider-DMDFRH6B.css} +0 -0
  504. /package/storybook-static/assets/{Flex-IXK2se1Y.css → useFlexClasses-IXK2se1Y.css} +0 -0
  505. /package/storybook-static/assets/{picker-DzBkX15M.css → usePickerTriggerController-DzBkX15M.css} +0 -0
@@ -130,7 +130,11 @@ function y({ label: t, description: n, disabled: r, className: o, onClear: c, er
130
130
  hasLabel: t != null,
131
131
  hasDescription: !!n,
132
132
  hasError: !!A
133
- }), I = k && (!!l || E);
133
+ }), I = k && (!!l || E), L = v({
134
+ endAdornment: x,
135
+ onClear: c,
136
+ disabled: r
137
+ }), R = _(x != null, !!c, C);
134
138
  return /* @__PURE__ */ s(m, {
135
139
  label: t,
136
140
  description: n,
@@ -143,13 +147,9 @@ function y({ label: t, description: n, disabled: r, className: o, onClear: c, er
143
147
  descriptionId: N,
144
148
  errorId: P,
145
149
  children: /* @__PURE__ */ s(h, {
146
- endAdornment: v({
147
- endAdornment: x,
148
- onClear: c,
149
- disabled: r
150
- }),
150
+ endAdornment: L,
151
151
  endAdornmentClassName: S,
152
- endAdornmentWidth: _(x != null, !!c, C),
152
+ endAdornmentWidth: R,
153
153
  children: ({ controlClassName: t }) => /* @__PURE__ */ s("input", {
154
154
  ...T,
155
155
  id: j,
@@ -183,7 +183,11 @@ function b({ label: r, description: o, disabled: c, className: f, onClear: p, er
183
183
  } : void 0, L = (e) => {
184
184
  let t = e.target.value;
185
185
  P(t), b(l(t)), g && y && y();
186
- };
186
+ }, R = v({
187
+ endAdornment: C,
188
+ onClear: I,
189
+ disabled: c
190
+ }), z = _(C != null, !!I, T);
187
191
  return /* @__PURE__ */ s(m, {
188
192
  label: r,
189
193
  description: o,
@@ -196,13 +200,9 @@ function b({ label: r, description: o, disabled: c, className: f, onClear: p, er
196
200
  descriptionId: A,
197
201
  errorId: j,
198
202
  children: /* @__PURE__ */ s(h, {
199
- endAdornment: v({
200
- endAdornment: C,
201
- onClear: I,
202
- disabled: c
203
- }),
203
+ endAdornment: R,
204
204
  endAdornmentClassName: w,
205
- endAdornmentWidth: _(C != null, !!I, T),
205
+ endAdornmentWidth: z,
206
206
  children: ({ controlClassName: t }) => /* @__PURE__ */ s("input", {
207
207
  ...D,
208
208
  id: O,
@@ -230,4 +230,4 @@ function S({ text: t }) {
230
230
  //#endregion
231
231
  export { b as a, p as c, h as i, d as l, x as n, y as o, g as r, m as s, S as t, u };
232
232
 
233
- //# sourceMappingURL=input-BCJfUdK_.js.map
233
+ //# sourceMappingURL=input-Bp6_Ucgr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input-BCJfUdK_.js","names":[],"sources":["../../src/input/Input.module.scss","../../src/input/lib/useInputFieldIds.ts","../../src/input/Input.tsx","../../src/input/InputErrorComponent.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.controlLayout {\n\tposition: relative;\n\twidth: 100%;\n}\n\n.input {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: var(--space-xs) var(--space-sm);\n\tfont-size: var(--font-size-md);\n\n\t--ui-color: var(--content-0);\n\t--ui-color-hover: var(--content-0);\n\t--ui-color-active: var(--content-0);\n}\n\n.inputNumber {\n\tappearance: textfield;\n\t-moz-appearance: textfield;\n\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n}\n\n.controlWithEndAdornment {\n\tpadding-right: calc(var(--input-end-adornment-width, var(--control-height)) + var(--space-sm));\n}\n\n.controlEndAdornment {\n\tposition: absolute;\n\theight: 100%;\n\ttop: 0;\n\tright: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n\t// max-width: calc(100% - (var(--space-md) * 2));\n\tmax-width: calc(100% - var(--space-md));\n}\n\n.endAdornmentGroup {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n}\n\n.clearButton {\n\twidth: 1.75em;\n\theight: 1.75em;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--content-1);\n\ttransition:\n\t\tcolor var(--transition-fast) ease,\n\t\tbackground-color var(--transition-fast) ease;\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t\tbackground-color: var(--status-info-soft);\n\t}\n\n\t&:focus-visible {\n\t\t@include focusVisible;\n\t}\n\n\t&:disabled {\n\t\tpointer-events: none;\n\t\topacity: 0.25;\n\t}\n}\n\n.error {\n\tposition: absolute;\n\tz-index: 11;\n\tbottom: calc(var(--space-xs) * -1);\n\tleft: 0;\n\tright: 0;\n\ttransform: translateY(100%);\n\t// font-size: var(--font-size-sm);\n\tcolor: var(--status-error-on-fill);\n\tbackground: var(--status-error-fill);\n\tborder-radius: var(--radius-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbox-shadow: var(--shadow-sm);\n\topacity: 0.9;\n}\n","import { useId } from \"react\";\n\nexport interface UseInputFieldIdsOptions {\n\tid?: string;\n\thasLabel?: boolean;\n\thasDescription?: boolean;\n\thasError?: boolean;\n}\n\nexport interface InputFieldIds {\n\tcontrolId: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tdescribedBy?: string;\n}\n\nexport function useInputFieldIds({ id: externalId, hasLabel, hasDescription, hasError }: UseInputFieldIdsOptions): InputFieldIds {\n\tconst autoId = useId();\n\tconst controlId = externalId ?? autoId;\n\tconst labelId = hasLabel ? `${controlId}-label` : undefined;\n\tconst descriptionId = hasDescription ? `${controlId}-description` : undefined;\n\tconst errorId = hasError ? `${controlId}-error` : undefined;\n\tconst describedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined;\n\n\treturn {\n\t\tcontrolId,\n\t\tlabelId,\n\t\tdescriptionId,\n\t\terrorId,\n\t\tdescribedBy\n\t};\n}\n","import React, { CSSProperties, InputHTMLAttributes, ReactNode, useEffect, useEffectEvent, useState } from \"react\";\n\nimport { toFiniteNumber } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport { UiBaseProps, UiSize } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./Input.module.scss\";\nimport { useInputFieldIds } from \"./lib/useInputFieldIds\";\n\nexport interface InputUIProps extends Omit<UiBaseProps<never>, \"value\" | \"onChange\"> {\n\tclassName?: string;\n\terror?: string;\n\tcontrolId?: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tchildren: React.ReactNode;\n}\n\nexport interface InputControlRenderProps {\n\tcontrolClassName?: string;\n}\n\nexport interface InputControlProps {\n\tclassName?: string;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n\tchildren: (props: InputControlRenderProps) => ReactNode;\n}\n\nexport interface InputClearButtonProps {\n\tonClick?: () => void;\n\tdisabled?: boolean;\n\tclassName?: string;\n\tariaLabel?: string;\n}\n\nfunction InputLabel({ label, controlId, labelId }: { label: React.ReactNode; controlId?: string; labelId?: string }) {\n\treturn (\n\t\t<label id={labelId} htmlFor={controlId} className={uiStyles.uiLabel}>\n\t\t\t{label}\n\t\t</label>\n\t);\n}\n\nexport function InputUILoading({\n\tlabel,\n\tdescription,\n\tsize,\n\tdisabled,\n\tclassName\n}: Pick<InputUIProps, \"label\" | \"description\" | \"size\" | \"disabled\" | \"className\">) {\n\tconst { controlId, labelId, descriptionId } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description\n\t});\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(uiStyles.uiElement, uiStyles.uiSizable, size && uiStyles[size as UiSize], uiStyles.disabled, className)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={cn(uiStyles.uiInputControlFake, \"skeletonLine\")} />\n\t\t</div>\n\t);\n}\n\n/**\n * Низкоуровневая оболочка поля ввода с общими элементами оформления.\n */\nexport function InputUI({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\terror,\n\tsize,\n\tcontrolId,\n\tlabelId,\n\tdescriptionId,\n\terrorId,\n\tchildren\n}: InputUIProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tuiStyles.uiElement,\n\t\t\t\tuiStyles.uiSizable,\n\t\t\t\tsize && uiStyles[size as UiSize],\n\t\t\t\tdisabled && uiStyles.disabled,\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={styles.controlLayout}>\n\t\t\t\t{children}\n\n\t\t\t\t{error && (\n\t\t\t\t\t<p id={errorId} className={styles.error} role=\"alert\">\n\t\t\t\t\t\t{error}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function InputControl({ className, endAdornment, endAdornmentClassName, endAdornmentWidth, children }: InputControlProps) {\n\tconst hasEndAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst style =\n\t\thasEndAdornment && endAdornmentWidth ? ({ \"--input-end-adornment-width\": endAdornmentWidth } as CSSProperties) : undefined;\n\n\treturn (\n\t\t<div className={cn(styles.controlLayout, className)} style={style}>\n\t\t\t{children({ controlClassName: hasEndAdornment ? styles.controlWithEndAdornment : undefined })}\n\t\t\t{hasEndAdornment && <div className={cn(styles.controlEndAdornment, endAdornmentClassName)}>{endAdornment}</div>}\n\t\t</div>\n\t);\n}\n\nexport function InputClearButton({ onClick, disabled, className, ariaLabel = \"Очистить значение\" }: InputClearButtonProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdisabled={disabled || !onClick}\n\t\t\tclassName={cn(styles.clearButton, \"flexCenter radiusSm\", className)}\n\t\t\tonClick={onClick}\n\t\t\taria-label={ariaLabel}>\n\t\t\t<XIcon />\n\t\t</button>\n\t);\n}\n\nfunction resolveEndAdornmentWidth(hasAdornment: boolean, hasClearAction: boolean, explicitWidth?: string) {\n\tif (explicitWidth) {\n\t\treturn explicitWidth;\n\t}\n\n\tif (hasAdornment && hasClearAction) {\n\t\treturn \"calc((var(--control-height) * 2) + var(--space-xs))\";\n\t}\n\n\tif (hasAdornment || hasClearAction) {\n\t\treturn \"var(--control-height)\";\n\t}\n\n\treturn undefined;\n}\n\nfunction createEndAdornment({ endAdornment, onClear, disabled }: { endAdornment?: ReactNode; onClear?: () => void; disabled?: boolean }) {\n\tif ((endAdornment === undefined || endAdornment === null) && !onClear) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<div className={styles.endAdornmentGroup}>\n\t\t\t{endAdornment}\n\t\t\t{onClear && <InputClearButton onClick={onClear} disabled={disabled} />}\n\t\t</div>\n\t);\n}\n\nexport interface BaseInputProps<T extends number | string | undefined, V = T>\n\textends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"type\" | \"defaultValue\" | \"onChange\">, UiBaseProps<T, V> {\n\tonClear?: () => void;\n\terror?: string;\n\tonClearError?: () => void;\n\tdefaultValue?: T;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n}\n\nexport interface InputTextProps extends BaseInputProps<string> {\n\ttype?: \"email\" | \"password\" | \"search\" | \"tel\" | \"text\" | \"url\";\n\n\t/**\n\t * Регулярное выражение для валидации всего введённого значения.\n\t * При несоответствии поле подсвечивается как невалидное, но текст не удаляется.\n\t * Пример: `/^\\d*$/`\n\t */\n\tallowedPattern?: RegExp;\n}\n\n/**\n * Базовое текстовое поле ввода для строковых значений.\n */\nexport function InputText({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tallowedPattern,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\ttype = \"text\",\n\t...props\n}: InputTextProps) {\n\tconst [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst newValue = e.target.value;\n\n\t\tif (allowedPattern !== undefined) {\n\t\t\tsetInternalInvalid(newValue !== \"\" && !allowedPattern.test(newValue));\n\t\t}\n\n\t\tonChange(newValue);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\tconst hasValue = Boolean(value && value.length > 0);\n\tconst visibleError = hasValue ? error : undefined;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!visibleError\n\t});\n\tconst isInvalid = hasValue && (!!error || internalInvalid);\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!onClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={visibleError}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\taria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tdata-invalid={isInvalid ? \"\" : undefined}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Числовое поле ввода с нормализацией значения и защитой от промежуточного невалидного ввода.\n */\nexport function InputNumber({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\t...props\n}: BaseInputProps<number | undefined>) {\n\tconst inputProps = props as InputHTMLAttributes<HTMLInputElement>;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\tconst [rawValue, setRawValue] = useState<string>(() => String(value));\n\t// const [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst syncRawValue = useEffectEvent((nextRaw: string) => {\n\t\tsetRawValue(nextRaw);\n\t\t// setInternalInvalid(false);\n\t});\n\n\tuseEffect(() => {\n\t\tconst nextRaw = value !== undefined && typeof value === \"number\" && !isNaN(value) ? String(value) : \"\";\n\t\tsyncRawValue(nextRaw);\n\t}, [value]);\n\n\tconst handleClear = onClear\n\t\t? () => {\n\t\t\t\tsetRawValue(\"\");\n\t\t\t\t// setInternalInvalid(false);\n\t\t\t\tonClear();\n\t\t\t}\n\t\t: undefined;\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst raw = e.target.value;\n\t\tsetRawValue(raw);\n\n\t\tconst parsed = toFiniteNumber(raw); // ?? value ?? 0;\n\n\t\tonChange(parsed);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\t// const isInvalid = !!error || internalInvalid;\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear: handleClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!handleClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...inputProps}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tinputMode=\"decimal\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={rawValue}\n\t\t\t\t\t\t// aria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, styles.inputNumber, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Совместимый алиас для `InputText`.\n */\nexport const Input = InputText;\n","import styles from \"../ui.module.scss\";\n\ninterface InputErrorComponentProps {\n\ttext: string;\n}\n\nexport function InputErrorComponent({ text }: InputErrorComponentProps) {\n\treturn <div className={styles.uiErrorElement}>{text}</div>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"input-Bp6_Ucgr.js","names":[],"sources":["../../src/input/Input.module.scss","../../src/input/lib/useInputFieldIds.ts","../../src/input/Input.tsx","../../src/input/InputErrorComponent.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.controlLayout {\n\tposition: relative;\n\twidth: 100%;\n}\n\n.input {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: var(--space-xs) var(--space-sm);\n\tfont-size: var(--font-size-md);\n\n\t--ui-color: var(--content-0);\n\t--ui-color-hover: var(--content-0);\n\t--ui-color-active: var(--content-0);\n}\n\n.inputNumber {\n\tappearance: textfield;\n\t-moz-appearance: textfield;\n\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n}\n\n.controlWithEndAdornment {\n\tpadding-right: calc(var(--input-end-adornment-width, var(--control-height)) + var(--space-sm));\n}\n\n.controlEndAdornment {\n\tposition: absolute;\n\theight: 100%;\n\ttop: 0;\n\tright: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n\t// max-width: calc(100% - (var(--space-md) * 2));\n\tmax-width: calc(100% - var(--space-md));\n}\n\n.endAdornmentGroup {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n}\n\n.clearButton {\n\twidth: 1.75em;\n\theight: 1.75em;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--content-1);\n\ttransition:\n\t\tcolor var(--transition-fast) ease,\n\t\tbackground-color var(--transition-fast) ease;\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t\tbackground-color: var(--status-info-soft);\n\t}\n\n\t&:focus-visible {\n\t\t@include focusVisible;\n\t}\n\n\t&:disabled {\n\t\tpointer-events: none;\n\t\topacity: 0.25;\n\t}\n}\n\n.error {\n\tposition: absolute;\n\tz-index: 11;\n\tbottom: calc(var(--space-xs) * -1);\n\tleft: 0;\n\tright: 0;\n\ttransform: translateY(100%);\n\t// font-size: var(--font-size-sm);\n\tcolor: var(--status-error-on-fill);\n\tbackground: var(--status-error-fill);\n\tborder-radius: var(--radius-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbox-shadow: var(--shadow-sm);\n\topacity: 0.9;\n}\n","import { useId } from \"react\";\n\nexport interface UseInputFieldIdsOptions {\n\tid?: string;\n\thasLabel?: boolean;\n\thasDescription?: boolean;\n\thasError?: boolean;\n}\n\nexport interface InputFieldIds {\n\tcontrolId: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tdescribedBy?: string;\n}\n\nexport function useInputFieldIds({ id: externalId, hasLabel, hasDescription, hasError }: UseInputFieldIdsOptions): InputFieldIds {\n\tconst autoId = useId();\n\tconst controlId = externalId ?? autoId;\n\tconst labelId = hasLabel ? `${controlId}-label` : undefined;\n\tconst descriptionId = hasDescription ? `${controlId}-description` : undefined;\n\tconst errorId = hasError ? `${controlId}-error` : undefined;\n\tconst describedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined;\n\n\treturn {\n\t\tcontrolId,\n\t\tlabelId,\n\t\tdescriptionId,\n\t\terrorId,\n\t\tdescribedBy\n\t};\n}\n","import React, { CSSProperties, InputHTMLAttributes, ReactNode, useEffect, useEffectEvent, useState } from \"react\";\n\nimport { toFiniteNumber } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport { UiBaseProps, UiSize } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./Input.module.scss\";\nimport { useInputFieldIds } from \"./lib/useInputFieldIds\";\n\nexport interface InputUIProps extends Omit<UiBaseProps<never>, \"value\" | \"onChange\"> {\n\tclassName?: string;\n\terror?: string;\n\tcontrolId?: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tchildren: React.ReactNode;\n}\n\nexport interface InputControlRenderProps {\n\tcontrolClassName?: string;\n}\n\nexport interface InputControlProps {\n\tclassName?: string;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n\tchildren: (props: InputControlRenderProps) => ReactNode;\n}\n\nexport interface InputClearButtonProps {\n\tonClick?: () => void;\n\tdisabled?: boolean;\n\tclassName?: string;\n\tariaLabel?: string;\n}\n\nfunction InputLabel({ label, controlId, labelId }: { label: React.ReactNode; controlId?: string; labelId?: string }) {\n\treturn (\n\t\t<label id={labelId} htmlFor={controlId} className={uiStyles.uiLabel}>\n\t\t\t{label}\n\t\t</label>\n\t);\n}\n\nexport function InputUILoading({\n\tlabel,\n\tdescription,\n\tsize,\n\tdisabled,\n\tclassName\n}: Pick<InputUIProps, \"label\" | \"description\" | \"size\" | \"disabled\" | \"className\">) {\n\tconst { controlId, labelId, descriptionId } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description\n\t});\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(uiStyles.uiElement, uiStyles.uiSizable, size && uiStyles[size as UiSize], uiStyles.disabled, className)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={cn(uiStyles.uiInputControlFake, \"skeletonLine\")} />\n\t\t</div>\n\t);\n}\n\n/**\n * Низкоуровневая оболочка поля ввода с общими элементами оформления.\n */\nexport function InputUI({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\terror,\n\tsize,\n\tcontrolId,\n\tlabelId,\n\tdescriptionId,\n\terrorId,\n\tchildren\n}: InputUIProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tuiStyles.uiElement,\n\t\t\t\tuiStyles.uiSizable,\n\t\t\t\tsize && uiStyles[size as UiSize],\n\t\t\t\tdisabled && uiStyles.disabled,\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={styles.controlLayout}>\n\t\t\t\t{children}\n\n\t\t\t\t{error && (\n\t\t\t\t\t<p id={errorId} className={styles.error} role=\"alert\">\n\t\t\t\t\t\t{error}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function InputControl({ className, endAdornment, endAdornmentClassName, endAdornmentWidth, children }: InputControlProps) {\n\tconst hasEndAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst style =\n\t\thasEndAdornment && endAdornmentWidth ? ({ \"--input-end-adornment-width\": endAdornmentWidth } as CSSProperties) : undefined;\n\n\treturn (\n\t\t<div className={cn(styles.controlLayout, className)} style={style}>\n\t\t\t{children({ controlClassName: hasEndAdornment ? styles.controlWithEndAdornment : undefined })}\n\t\t\t{hasEndAdornment && <div className={cn(styles.controlEndAdornment, endAdornmentClassName)}>{endAdornment}</div>}\n\t\t</div>\n\t);\n}\n\nexport function InputClearButton({ onClick, disabled, className, ariaLabel = \"Очистить значение\" }: InputClearButtonProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdisabled={disabled || !onClick}\n\t\t\tclassName={cn(styles.clearButton, \"flexCenter radiusSm\", className)}\n\t\t\tonClick={onClick}\n\t\t\taria-label={ariaLabel}>\n\t\t\t<XIcon />\n\t\t</button>\n\t);\n}\n\nfunction resolveEndAdornmentWidth(hasAdornment: boolean, hasClearAction: boolean, explicitWidth?: string) {\n\tif (explicitWidth) {\n\t\treturn explicitWidth;\n\t}\n\n\tif (hasAdornment && hasClearAction) {\n\t\treturn \"calc((var(--control-height) * 2) + var(--space-xs))\";\n\t}\n\n\tif (hasAdornment || hasClearAction) {\n\t\treturn \"var(--control-height)\";\n\t}\n\n\treturn undefined;\n}\n\nfunction createEndAdornment({ endAdornment, onClear, disabled }: { endAdornment?: ReactNode; onClear?: () => void; disabled?: boolean }) {\n\tif ((endAdornment === undefined || endAdornment === null) && !onClear) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<div className={styles.endAdornmentGroup}>\n\t\t\t{endAdornment}\n\t\t\t{onClear && <InputClearButton onClick={onClear} disabled={disabled} />}\n\t\t</div>\n\t);\n}\n\nexport interface BaseInputProps<T extends number | string | undefined, V = T>\n\textends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"type\" | \"defaultValue\" | \"onChange\">, UiBaseProps<T, V> {\n\tonClear?: () => void;\n\terror?: string;\n\tonClearError?: () => void;\n\tdefaultValue?: T;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n}\n\nexport interface InputTextProps extends BaseInputProps<string> {\n\ttype?: \"email\" | \"password\" | \"search\" | \"tel\" | \"text\" | \"url\";\n\n\t/**\n\t * Регулярное выражение для валидации всего введённого значения.\n\t * При несоответствии поле подсвечивается как невалидное, но текст не удаляется.\n\t * Пример: `/^\\d*$/`\n\t */\n\tallowedPattern?: RegExp;\n}\n\n/**\n * Базовое текстовое поле ввода для строковых значений.\n */\nexport function InputText({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tallowedPattern,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\ttype = \"text\",\n\t...props\n}: InputTextProps) {\n\tconst [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst newValue = e.target.value;\n\n\t\tif (allowedPattern !== undefined) {\n\t\t\tsetInternalInvalid(newValue !== \"\" && !allowedPattern.test(newValue));\n\t\t}\n\n\t\tonChange(newValue);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\tconst hasValue = Boolean(value && value.length > 0);\n\tconst visibleError = hasValue ? error : undefined;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!visibleError\n\t});\n\tconst isInvalid = hasValue && (!!error || internalInvalid);\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!onClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={visibleError}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\taria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tdata-invalid={isInvalid ? \"\" : undefined}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Числовое поле ввода с нормализацией значения и защитой от промежуточного невалидного ввода.\n */\nexport function InputNumber({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\t...props\n}: BaseInputProps<number | undefined>) {\n\tconst inputProps = props as InputHTMLAttributes<HTMLInputElement>;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\tconst [rawValue, setRawValue] = useState<string>(() => String(value));\n\t// const [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst syncRawValue = useEffectEvent((nextRaw: string) => {\n\t\tsetRawValue(nextRaw);\n\t\t// setInternalInvalid(false);\n\t});\n\n\tuseEffect(() => {\n\t\tconst nextRaw = value !== undefined && typeof value === \"number\" && !isNaN(value) ? String(value) : \"\";\n\t\tsyncRawValue(nextRaw);\n\t}, [value]);\n\n\tconst handleClear = onClear\n\t\t? () => {\n\t\t\t\tsetRawValue(\"\");\n\t\t\t\t// setInternalInvalid(false);\n\t\t\t\tonClear();\n\t\t\t}\n\t\t: undefined;\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst raw = e.target.value;\n\t\tsetRawValue(raw);\n\n\t\tconst parsed = toFiniteNumber(raw); // ?? value ?? 0;\n\n\t\tonChange(parsed);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\t// const isInvalid = !!error || internalInvalid;\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear: handleClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!handleClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...inputProps}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tinputMode=\"decimal\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={rawValue}\n\t\t\t\t\t\t// aria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, styles.inputNumber, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Совместимый алиас для `InputText`.\n */\nexport const Input = InputText;\n","import styles from \"../ui.module.scss\";\n\ninterface InputErrorComponentProps {\n\ttext: string;\n}\n\nexport function InputErrorComponent({ text }: InputErrorComponentProps) {\n\treturn <div className={styles.uiErrorElement}>{text}</div>;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./ui.module-BisoTevy.js";
2
- import { i as t, l as n, s as r } from "./input-BCJfUdK_.js";
2
+ import { i as t, l as n, s as r } from "./input-Bp6_Ucgr.js";
3
3
  import { useCallback as i, useRef as a } from "react";
4
4
  import { cn as o, handleKeyboardActivation as s } from "@ryuzaki13/react-foundation-lib/utils";
5
5
  import { XIcon as c } from "lucide-react";
@@ -138,4 +138,4 @@ function _(c) {
138
138
  //#endregion
139
139
  export { g as n, _ as t };
140
140
 
141
- //# sourceMappingURL=input-files-Dcc5K-_1.js.map
141
+ //# sourceMappingURL=input-files-D1JzSw_Y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input-files-Dcc5K-_1.js","names":[],"sources":["../../src/input-files/InputFiles.module.scss","../../src/input-files/InputFilesList.tsx","../../src/input-files/InputFiles.tsx"],"sourcesContent":["/* Контрол, имитирующий внешний вид InputText */\n.control {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: 0 var(--space-sm);\n\tfont-size: var(--font-size-md);\n\tcursor: pointer;\n\n\tdisplay: flex;\n\talign-items: center;\n}\n\n/* Скрытый нативный input[type=\"file\"] */\n.hiddenInput {\n\tposition: absolute;\n\twidth: 0;\n\theight: 0;\n\topacity: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n}\n\n/* Список выбранных файлов */\n.fileList {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--space-xs);\n\tmargin-top: var(--space-xs);\n}\n\n/* Элемент списка — строка с именем файла и кнопкой удаления */\n.fileItem {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbackground-color: var(--surface-2);\n\tborder-radius: var(--radius-sm);\n\t// font-size: var(--font-size-sm);\n}\n\n/* Имя файла — обрезка с троеточием */\n.fileItemName {\n\tflex: 1;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n/* Кнопка удаления файла из списка */\n.removeButton {\n\tflex-shrink: 0;\n\twidth: 1.25em;\n\theight: 1.25em;\n\tcolor: var(--content-2);\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t}\n}\n","import { useCallback } from \"react\";\n\nimport { ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport styles from \"./InputFiles.module.scss\";\n\ninterface InputFilesListProps<TFile extends ReadFileResult> {\n\tfiles: TFile[];\n\tonChange: (files: TFile[]) => void;\n}\n\nexport function InputFilesList<TFile extends ReadFileResult>({ files, onChange }: InputFilesListProps<TFile>) {\n\tconst handleRemove = useCallback(\n\t\t(index: number) => {\n\t\t\tonChange(files.filter((_, i) => i !== index));\n\t\t},\n\t\t[files, onChange]\n\t);\n\n\tif (!files || !files.length) return null;\n\n\treturn (\n\t\t<ul className={styles.fileList}>\n\t\t\t{files.map((item, index) => (\n\t\t\t\t<li key={`${item.meta.name}-${item.meta.lastModified}`} className={styles.fileItem}>\n\t\t\t\t\t<span className={styles.fileItemName}>{item.meta.name}</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={cn(styles.removeButton, \"flexCenter\")}\n\t\t\t\t\t\tonClick={() => handleRemove(index)}\n\t\t\t\t\t\taria-label={`Удалить ${item.meta.name}`}>\n\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n","import { useCallback, useRef } from \"react\";\n\nimport { assertValidAccept, assertValidAllowedMime, readFile, ReadFileError, ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn, handleKeyboardActivation } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputFiles.module.scss\";\nimport { InputFilesList } from \"./InputFilesList\";\n\ninterface InputFilesCommonProps extends Omit<UiBaseProps<undefined>, \"value\" | \"onChange\"> {\n\t/** Callback ошибки чтения файла */\n\tonReadError?: (error: ReadFileError) => void;\n\n\t/** HTML-атрибут accept для нативного input[type=\"file\"] (например `[\".pdf\", \".docx\"]`) */\n\taccept?: readonly string[];\n\t/** Список допустимых MIME-типов — передаётся в readFile */\n\tallowedMime?: readonly string[];\n\t/** Максимальный размер одного файла в байтах */\n\tmaxBytes?: number;\n\t/** Максимальное количество файлов. При достижении лимита input блокируется */\n\tmaxFiles?: number;\n\n\t/** Текст ошибки под полем */\n\terror?: string;\n\t/** Callback сброса ошибки */\n\tonClearError?: () => void;\n\t/** CSS-класс обёртки */\n\tclassName?: string;\n}\n\ntype InputFilesDataUrlResult = Extract<ReadFileResult, { mode: \"data-url\" }>;\ntype InputFilesArrayBufferResult = Extract<ReadFileResult, { mode: \"array-buffer\" }>;\n\n/**\n * Пропсы компонента InputFiles.\n *\n * Компонент предназначен для выбора нескольких файлов.\n * Выбранные файлы отображаются списком под полем ввода,\n * каждый с кнопкой удаления (крестик).\n *\n * В onChange передаётся обновлённый массив результатов readFile.\n */\nexport type InputFilesProps =\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesDataUrlResult[];\n\t\t\tonChange: (value: InputFilesDataUrlResult[]) => void;\n\t\t\t/** Режим чтения: \"data-url\" по умолчанию */\n\t\t\treadMode?: \"data-url\";\n\t })\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesArrayBufferResult[];\n\t\t\tonChange: (value: InputFilesArrayBufferResult[]) => void;\n\t\t\t/** Режим чтения файла как ArrayBuffer */\n\t\t\treadMode: \"array-buffer\";\n\t });\n\n/**\n * InputFiles — компонент выбора нескольких файлов.\n *\n * Поле стилизовано как InputText. При клике открывается нативный\n * диалог с multiple. Каждый выбранный файл читается через readFile\n * и добавляется в массив value.\n *\n * Список выбранных файлов отображается под полем.\n * Каждый файл можно удалить кнопкой «крестик».\n *\n * InputFiles типизирует массив по `readMode`.\n * Если `readMode` не задан или равен `\"data-url\"`, в `value` и `onChange`\n * используется массив объектов с `dataUrl`. Если `readMode` равен\n * `\"array-buffer\"`, используется массив объектов с `buffer`.\n */\nexport function InputFiles(props: InputFilesProps) {\n\tconst {\n\t\tvalue,\n\t\tonReadError,\n\t\taccept,\n\t\tallowedMime,\n\t\tmaxBytes,\n\t\tmaxFiles,\n\t\tlabel,\n\t\tdescription,\n\t\tplaceholder = \"Выберите файлы\",\n\t\tdisabled,\n\t\tsize,\n\t\terror,\n\t\tonClearError,\n\t\tclassName\n\t} = props;\n\n\tassertValidAllowedMime(allowedMime);\n\tassertValidAccept(accept);\n\n\t/** Реф на скрытый нативный input[type=\"file\"] */\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\t/** Достигнут ли лимит файлов */\n\tconst isLimitReached = typeof maxFiles === \"number\" && value.length >= maxFiles;\n\n\t/**\n\t * Обработчик выбора файлов из нативного диалога.\n\t * Каждый файл читается через readFile.\n\t * Успешно прочитанные файлы добавляются к текущему массиву value.\n\t */\n\tconst handleChange = useCallback(\n\t\tasync (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tconst files = e.target.files;\n\t\t\tif (!files || files.length === 0) return;\n\n\t\t\tconst selectedFiles = Array.from(files);\n\n\t\t\t// Сбрасываем значение input чтобы можно было выбрать те же файлы повторно\n\t\t\te.target.value = \"\";\n\n\t\t\t// Сбрасываем ошибку при выборе новых файлов\n\t\t\tif (error && onClearError) onClearError();\n\n\t\t\t// Определяем сколько файлов можно ещё добавить\n\t\t\tconst remaining = typeof maxFiles === \"number\" ? maxFiles - value.length : selectedFiles.length;\n\t\t\tconst filesToProcess = selectedFiles.slice(0, remaining);\n\n\t\t\tif (props.readMode === \"array-buffer\") {\n\t\t\t\t// Читаем файлы как ArrayBuffer и сохраняем точный тип массива для потребителя.\n\t\t\t\tconst results: InputFilesArrayBufferResult[] = [];\n\n\t\t\t\tfor (const file of filesToProcess) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes, mode: \"array-buffer\" });\n\t\t\t\t\t\tresults.push(result);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (results.length > 0) {\n\t\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Читаем файлы как Data URL и сохраняем точный тип массива для потребителя.\n\t\t\tconst results: InputFilesDataUrlResult[] = [];\n\t\t\tfor (const file of filesToProcess) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes });\n\t\t\t\t\tresults.push(result);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (results.length > 0) {\n\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t}\n\t\t},\n\t\t[props, maxFiles, value.length, allowedMime, maxBytes, onReadError, error, onClearError]\n\t);\n\n\t/** Клик по видимому контролу открывает нативный диалог */\n\tconst handleClick = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\tconst filesList =\n\t\tprops.readMode === \"array-buffer\" ? (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t) : (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={controlId}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={(accept ?? allowedMime)?.join(\",\")}\n\t\t\t\tmultiple\n\t\t\t\tdisabled={disabled || isLimitReached}\n\t\t\t\tclassName={styles.hiddenInput}\n\t\t\t\tonChange={handleChange}\n\t\t\t\ttabIndex={-1}\n\t\t\t/>\n\n\t\t\t<InputControl>\n\t\t\t\t{() => (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabIndex={disabled || isLimitReached ? -1 : 0}\n\t\t\t\t\t\tonClick={handleClick}\n\t\t\t\t\t\tonKeyDown={(event) => handleKeyboardActivation(event, handleClick, { disabled: disabled || isLimitReached })}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.control, !!error && \"invalid\")}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-disabled={disabled || isLimitReached}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}>\n\t\t\t\t\t\t<span className={uiStyles.uiPlaceholder}>{isLimitReached ? `Максимум ${maxFiles} файлов` : placeholder}</span>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\n\t\t\t{/* Список выбранных файлов */}\n\t\t\t{filesList}\n\t\t</InputUI>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"input-files-D1JzSw_Y.js","names":[],"sources":["../../src/input-files/InputFiles.module.scss","../../src/input-files/InputFilesList.tsx","../../src/input-files/InputFiles.tsx"],"sourcesContent":["/* Контрол, имитирующий внешний вид InputText */\n.control {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: 0 var(--space-sm);\n\tfont-size: var(--font-size-md);\n\tcursor: pointer;\n\n\tdisplay: flex;\n\talign-items: center;\n}\n\n/* Скрытый нативный input[type=\"file\"] */\n.hiddenInput {\n\tposition: absolute;\n\twidth: 0;\n\theight: 0;\n\topacity: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n}\n\n/* Список выбранных файлов */\n.fileList {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--space-xs);\n\tmargin-top: var(--space-xs);\n}\n\n/* Элемент списка — строка с именем файла и кнопкой удаления */\n.fileItem {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbackground-color: var(--surface-2);\n\tborder-radius: var(--radius-sm);\n\t// font-size: var(--font-size-sm);\n}\n\n/* Имя файла — обрезка с троеточием */\n.fileItemName {\n\tflex: 1;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n/* Кнопка удаления файла из списка */\n.removeButton {\n\tflex-shrink: 0;\n\twidth: 1.25em;\n\theight: 1.25em;\n\tcolor: var(--content-2);\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t}\n}\n","import { useCallback } from \"react\";\n\nimport { ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport styles from \"./InputFiles.module.scss\";\n\ninterface InputFilesListProps<TFile extends ReadFileResult> {\n\tfiles: TFile[];\n\tonChange: (files: TFile[]) => void;\n}\n\nexport function InputFilesList<TFile extends ReadFileResult>({ files, onChange }: InputFilesListProps<TFile>) {\n\tconst handleRemove = useCallback(\n\t\t(index: number) => {\n\t\t\tonChange(files.filter((_, i) => i !== index));\n\t\t},\n\t\t[files, onChange]\n\t);\n\n\tif (!files || !files.length) return null;\n\n\treturn (\n\t\t<ul className={styles.fileList}>\n\t\t\t{files.map((item, index) => (\n\t\t\t\t<li key={`${item.meta.name}-${item.meta.lastModified}`} className={styles.fileItem}>\n\t\t\t\t\t<span className={styles.fileItemName}>{item.meta.name}</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={cn(styles.removeButton, \"flexCenter\")}\n\t\t\t\t\t\tonClick={() => handleRemove(index)}\n\t\t\t\t\t\taria-label={`Удалить ${item.meta.name}`}>\n\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n","import { useCallback, useRef } from \"react\";\n\nimport { assertValidAccept, assertValidAllowedMime, readFile, ReadFileError, ReadFileResult } from \"@ryuzaki13/react-foundation-lib/file\";\nimport { cn, handleKeyboardActivation } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { InputControl, InputUI, useInputFieldIds } from \"../input\";\nimport { UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./InputFiles.module.scss\";\nimport { InputFilesList } from \"./InputFilesList\";\n\ninterface InputFilesCommonProps extends Omit<UiBaseProps<undefined>, \"value\" | \"onChange\"> {\n\t/** Callback ошибки чтения файла */\n\tonReadError?: (error: ReadFileError) => void;\n\n\t/** HTML-атрибут accept для нативного input[type=\"file\"] (например `[\".pdf\", \".docx\"]`) */\n\taccept?: readonly string[];\n\t/** Список допустимых MIME-типов — передаётся в readFile */\n\tallowedMime?: readonly string[];\n\t/** Максимальный размер одного файла в байтах */\n\tmaxBytes?: number;\n\t/** Максимальное количество файлов. При достижении лимита input блокируется */\n\tmaxFiles?: number;\n\n\t/** Текст ошибки под полем */\n\terror?: string;\n\t/** Callback сброса ошибки */\n\tonClearError?: () => void;\n\t/** CSS-класс обёртки */\n\tclassName?: string;\n}\n\ntype InputFilesDataUrlResult = Extract<ReadFileResult, { mode: \"data-url\" }>;\ntype InputFilesArrayBufferResult = Extract<ReadFileResult, { mode: \"array-buffer\" }>;\n\n/**\n * Пропсы компонента InputFiles.\n *\n * Компонент предназначен для выбора нескольких файлов.\n * Выбранные файлы отображаются списком под полем ввода,\n * каждый с кнопкой удаления (крестик).\n *\n * В onChange передаётся обновлённый массив результатов readFile.\n */\nexport type InputFilesProps =\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesDataUrlResult[];\n\t\t\tonChange: (value: InputFilesDataUrlResult[]) => void;\n\t\t\t/** Режим чтения: \"data-url\" по умолчанию */\n\t\t\treadMode?: \"data-url\";\n\t })\n\t| (InputFilesCommonProps & {\n\t\t\tvalue: InputFilesArrayBufferResult[];\n\t\t\tonChange: (value: InputFilesArrayBufferResult[]) => void;\n\t\t\t/** Режим чтения файла как ArrayBuffer */\n\t\t\treadMode: \"array-buffer\";\n\t });\n\n/**\n * InputFiles — компонент выбора нескольких файлов.\n *\n * Поле стилизовано как InputText. При клике открывается нативный\n * диалог с multiple. Каждый выбранный файл читается через readFile\n * и добавляется в массив value.\n *\n * Список выбранных файлов отображается под полем.\n * Каждый файл можно удалить кнопкой «крестик».\n *\n * InputFiles типизирует массив по `readMode`.\n * Если `readMode` не задан или равен `\"data-url\"`, в `value` и `onChange`\n * используется массив объектов с `dataUrl`. Если `readMode` равен\n * `\"array-buffer\"`, используется массив объектов с `buffer`.\n */\nexport function InputFiles(props: InputFilesProps) {\n\tconst {\n\t\tvalue,\n\t\tonReadError,\n\t\taccept,\n\t\tallowedMime,\n\t\tmaxBytes,\n\t\tmaxFiles,\n\t\tlabel,\n\t\tdescription,\n\t\tplaceholder = \"Выберите файлы\",\n\t\tdisabled,\n\t\tsize,\n\t\terror,\n\t\tonClearError,\n\t\tclassName\n\t} = props;\n\n\tassertValidAllowedMime(allowedMime);\n\tassertValidAccept(accept);\n\n\t/** Реф на скрытый нативный input[type=\"file\"] */\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\t/** Достигнут ли лимит файлов */\n\tconst isLimitReached = typeof maxFiles === \"number\" && value.length >= maxFiles;\n\n\t/**\n\t * Обработчик выбора файлов из нативного диалога.\n\t * Каждый файл читается через readFile.\n\t * Успешно прочитанные файлы добавляются к текущему массиву value.\n\t */\n\tconst handleChange = useCallback(\n\t\tasync (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tconst files = e.target.files;\n\t\t\tif (!files || files.length === 0) return;\n\n\t\t\tconst selectedFiles = Array.from(files);\n\n\t\t\t// Сбрасываем значение input чтобы можно было выбрать те же файлы повторно\n\t\t\te.target.value = \"\";\n\n\t\t\t// Сбрасываем ошибку при выборе новых файлов\n\t\t\tif (error && onClearError) onClearError();\n\n\t\t\t// Определяем сколько файлов можно ещё добавить\n\t\t\tconst remaining = typeof maxFiles === \"number\" ? maxFiles - value.length : selectedFiles.length;\n\t\t\tconst filesToProcess = selectedFiles.slice(0, remaining);\n\n\t\t\tif (props.readMode === \"array-buffer\") {\n\t\t\t\t// Читаем файлы как ArrayBuffer и сохраняем точный тип массива для потребителя.\n\t\t\t\tconst results: InputFilesArrayBufferResult[] = [];\n\n\t\t\t\tfor (const file of filesToProcess) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes, mode: \"array-buffer\" });\n\t\t\t\t\t\tresults.push(result);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (results.length > 0) {\n\t\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Читаем файлы как Data URL и сохраняем точный тип массива для потребителя.\n\t\t\tconst results: InputFilesDataUrlResult[] = [];\n\t\t\tfor (const file of filesToProcess) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await readFile(file, { allowedMime, maxBytes });\n\t\t\t\t\tresults.push(result);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof ReadFileError && onReadError) {\n\t\t\t\t\t\tonReadError(err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (results.length > 0) {\n\t\t\t\tprops.onChange([...props.value, ...results]);\n\t\t\t}\n\t\t},\n\t\t[props, maxFiles, value.length, allowedMime, maxBytes, onReadError, error, onClearError]\n\t);\n\n\t/** Клик по видимому контролу открывает нативный диалог */\n\tconst handleClick = useCallback(() => {\n\t\tinputRef.current?.click();\n\t}, []);\n\n\tconst filesList =\n\t\tprops.readMode === \"array-buffer\" ? (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t) : (\n\t\t\t<InputFilesList files={props.value} onChange={props.onChange} />\n\t\t);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\tid={controlId}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={(accept ?? allowedMime)?.join(\",\")}\n\t\t\t\tmultiple\n\t\t\t\tdisabled={disabled || isLimitReached}\n\t\t\t\tclassName={styles.hiddenInput}\n\t\t\t\tonChange={handleChange}\n\t\t\t\ttabIndex={-1}\n\t\t\t/>\n\n\t\t\t<InputControl>\n\t\t\t\t{() => (\n\t\t\t\t\t<div\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabIndex={disabled || isLimitReached ? -1 : 0}\n\t\t\t\t\t\tonClick={handleClick}\n\t\t\t\t\t\tonKeyDown={(event) => handleKeyboardActivation(event, handleClick, { disabled: disabled || isLimitReached })}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.control, !!error && \"invalid\")}\n\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\taria-invalid={!!error || undefined}\n\t\t\t\t\t\taria-disabled={disabled || isLimitReached}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}>\n\t\t\t\t\t\t<span className={uiStyles.uiPlaceholder}>{isLimitReached ? `Максимум ${maxFiles} файлов` : placeholder}</span>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\n\t\t\t{/* Список выбранных файлов */}\n\t\t\t{filesList}\n\t\t</InputUI>\n\t);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { n as e } from "./input-BCJfUdK_.js";
1
+ import { n as e } from "./input-Bp6_Ucgr.js";
2
2
  import { useState as t } from "react";
3
3
  import { jsx as n } from "react/jsx-runtime";
4
4
  //#region src/input-search/InputSearch.tsx
@@ -27,4 +27,4 @@ function r({ onChange: r, ...i }) {
27
27
  //#endregion
28
28
  export { r as t };
29
29
 
30
- //# sourceMappingURL=input-search-B7HmrAM7.js.map
30
+ //# sourceMappingURL=input-search-Bkhcinru.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input-search-B7HmrAM7.js","names":[],"sources":["../../src/input-search/InputSearch.tsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nimport { BaseInputProps, Input } from \"../input\";\n\ninterface SearchInputProps extends BaseInputProps<string> {\n\tonChange: (value: string) => void;\n}\n\nexport function InputSearch({ onChange, ...props }: SearchInputProps) {\n\tconst [searchTerm, setSearchTerm] = useState(() => props.defaultValue ?? props.value ?? \"\");\n\tconst [previousSearch, setPreviousSearch] = useState(() => props.defaultValue ?? props.value ?? \"\");\n\n\tconst handleSearch = (term: string) => {\n\t\tconst changedTerm = term.trim();\n\n\t\t// Проверяем, изменилось ли значение с предыдущего поиска\n\t\tif (changedTerm === previousSearch) return;\n\n\t\tsetPreviousSearch(changedTerm);\n\t\tonChange(changedTerm);\n\t};\n\n\tconst handleClear = () => {\n\t\tsetSearchTerm(\"\");\n\t\tsetPreviousSearch(\"\");\n\t\tonChange(\"\");\n\t};\n\n\tconst handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\tif (event.key === \"Enter\") {\n\t\t\tevent.preventDefault();\n\t\t\thandleSearch(searchTerm);\n\t\t}\n\t};\n\n\tconst handleBlur = () => {\n\t\thandleSearch(searchTerm);\n\t};\n\n\tconst handleChange = (value: string) => {\n\t\tsetSearchTerm(value);\n\t\t// Не вызываем onSearch здесь - только по Enter/blur\n\t};\n\n\treturn (\n\t\t<Input {...props} value={searchTerm} onChange={handleChange} onKeyDown={handleKeyDown} onBlur={handleBlur} onClear={handleClear} />\n\t);\n}\n"],"mappings":";;;;AAQA,SAAgB,EAAY,EAAE,aAAU,GAAG,KAA2B;CACrE,IAAM,CAAC,GAAY,KAAiB,QAAe,EAAM,gBAAgB,EAAM,SAAS,EAAE,GACpF,CAAC,GAAgB,KAAqB,QAAe,EAAM,gBAAgB,EAAM,SAAS,EAAE,GAE5F,KAAgB,MAAiB;EACtC,IAAM,IAAc,EAAK,KAAK;EAG1B,MAAgB,MAEpB,EAAkB,CAAW,GAC7B,EAAS,CAAW;CACrB,GAEM,UAAoB;EAGzB,AAFA,EAAc,EAAE,GAChB,EAAkB,EAAE,GACpB,EAAS,EAAE;CACZ,GAEM,KAAiB,MAAiD;EACvE,AAAI,EAAM,QAAQ,YACjB,EAAM,eAAe,GACrB,EAAa,CAAU;CAEzB,GAEM,UAAmB;EACxB,EAAa,CAAU;CACxB,GAEM,KAAgB,MAAkB;EACvC,EAAc,CAAK;CAEpB;CAEA,OACC,kBAAC,GAAD;EAAO,GAAI;EAAO,OAAO;EAAY,UAAU;EAAc,WAAW;EAAe,QAAQ;EAAY,SAAS;CAAc,CAAA;AAEpI"}
1
+ {"version":3,"file":"input-search-Bkhcinru.js","names":[],"sources":["../../src/input-search/InputSearch.tsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nimport { BaseInputProps, Input } from \"../input\";\n\ninterface SearchInputProps extends BaseInputProps<string> {\n\tonChange: (value: string) => void;\n}\n\nexport function InputSearch({ onChange, ...props }: SearchInputProps) {\n\tconst [searchTerm, setSearchTerm] = useState(() => props.defaultValue ?? props.value ?? \"\");\n\tconst [previousSearch, setPreviousSearch] = useState(() => props.defaultValue ?? props.value ?? \"\");\n\n\tconst handleSearch = (term: string) => {\n\t\tconst changedTerm = term.trim();\n\n\t\t// Проверяем, изменилось ли значение с предыдущего поиска\n\t\tif (changedTerm === previousSearch) return;\n\n\t\tsetPreviousSearch(changedTerm);\n\t\tonChange(changedTerm);\n\t};\n\n\tconst handleClear = () => {\n\t\tsetSearchTerm(\"\");\n\t\tsetPreviousSearch(\"\");\n\t\tonChange(\"\");\n\t};\n\n\tconst handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n\t\tif (event.key === \"Enter\") {\n\t\t\tevent.preventDefault();\n\t\t\thandleSearch(searchTerm);\n\t\t}\n\t};\n\n\tconst handleBlur = () => {\n\t\thandleSearch(searchTerm);\n\t};\n\n\tconst handleChange = (value: string) => {\n\t\tsetSearchTerm(value);\n\t\t// Не вызываем onSearch здесь - только по Enter/blur\n\t};\n\n\treturn (\n\t\t<Input {...props} value={searchTerm} onChange={handleChange} onKeyDown={handleKeyDown} onBlur={handleBlur} onClear={handleClear} />\n\t);\n}\n"],"mappings":";;;;AAQA,SAAgB,EAAY,EAAE,aAAU,GAAG,KAA2B;CACrE,IAAM,CAAC,GAAY,KAAiB,QAAe,EAAM,gBAAgB,EAAM,SAAS,EAAE,GACpF,CAAC,GAAgB,KAAqB,QAAe,EAAM,gBAAgB,EAAM,SAAS,EAAE,GAE5F,KAAgB,MAAiB;EACtC,IAAM,IAAc,EAAK,KAAK;EAG1B,MAAgB,MAEpB,EAAkB,CAAW,GAC7B,EAAS,CAAW;CACrB,GAEM,UAAoB;EAGzB,AAFA,EAAc,EAAE,GAChB,EAAkB,EAAE,GACpB,EAAS,EAAE;CACZ,GAEM,KAAiB,MAAiD;EACvE,AAAI,EAAM,QAAQ,YACjB,EAAM,eAAe,GACrB,EAAa,CAAU;CAEzB,GAEM,UAAmB;EACxB,EAAa,CAAU;CACxB,GAEM,KAAgB,MAAkB;EACvC,EAAc,CAAK;CAEpB;CAEA,OACC,kBAAC,GAAD;EAAO,GAAI;EAAO,OAAO;EAAY,UAAU;EAAc,WAAW;EAAe,QAAQ;EAAY,SAAS;CAAc,CAAA;AAEpI"}
@@ -1,6 +1,6 @@
1
- import { n as e } from "./popover-xJJqy1v6.js";
1
+ import { n as e } from "./popover-CGU3MlsH.js";
2
2
  import { Text as t } from "../text/index.js";
3
- import { n } from "./flex-DYZ0IbU6.js";
3
+ import { n } from "./flex-C7njxZ74.js";
4
4
  import { PolymorphicComponent as r } from "../polymorphic/index.js";
5
5
  import { Suspense as i, forwardRef as a, useCallback as o, useEffect as s, useRef as c, useState as l, useSyncExternalStore as u } from "react";
6
6
  import { cn as d } from "@ryuzaki13/react-foundation-lib/utils";
@@ -290,4 +290,4 @@ function $({ as: e, state: t, className: n, ...i }) {
290
290
  //#endregion
291
291
  export { k as _, q as a, T as b, G as c, z as d, R as f, j as g, M as h, J as i, W as l, I as m, Y as n, Z as o, L as p, Q as r, X as s, $ as t, B as u, D as v, E as y };
292
292
 
293
- //# sourceMappingURL=misc-DIF5h9ba.js.map
293
+ //# sourceMappingURL=misc-BYxxlJz6.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"misc-DIF5h9ba.js","names":[],"sources":["../../src/misc/AnimatedLogo.module.scss","../../src/misc/AnimatedLogo.tsx","../../src/misc/AnimatedLogoSegment.tsx","../../src/misc/CopyTextWrapper.tsx","../../src/misc/IconWrapper.module.scss","../../src/misc/IconWrapper.tsx","../../src/misc/LoadingMessage.module.scss","../../src/misc/Message.tsx","../../src/misc/LoadingMessage.tsx","../../src/misc/LazyDynamicComponent.tsx","../../src/misc/SkeletonLine.tsx","../../src/misc/LazyValue.tsx","../../src/misc/NoData.tsx","../../src/misc/Notice.tsx","../../src/misc/OneStepScroller.module.scss","../../src/misc/OneStepScroller.tsx","../../src/misc/Scrollable.tsx","../../src/misc/State.module.scss","../../src/misc/StateIcon.tsx","../../src/misc/StateWrapper.tsx"],"sourcesContent":[".logo {\n\tsvg {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\theight: auto;\n\t}\n}\n\n.segment {\n\topacity: 0.2;\n\tanimation: pulseSteps 2s ease-in-out infinite;\n}\n\n@keyframes pulseSteps {\n\t0% {\n\t\topacity: 0.2;\n\t}\n\n\t35%,\n\t55% {\n\t\topacity: 1;\n\t}\n\n\t100% {\n\t\topacity: 0.2;\n\t}\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.segment {\n\t\tanimation: none;\n\t\topacity: 1;\n\t}\n}\n","import { type ComponentPropsWithoutRef, type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./AnimatedLogo.module.scss\";\n\ntype AnimatedLogoProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n\tchildren: ReactNode;\n};\n\n/**\n * Контейнер анимированного логотипа без брендовой SVG-разметки.\n * Host-проект передаёт собственный `svg`, а его визуальные части оборачивает в `AnimatedLogoSegment`.\n */\nexport function AnimatedLogo({ children, className, ...htmlProps }: AnimatedLogoProps) {\n\treturn (\n\t\t<div {...htmlProps} className={cn(styles.logo, className)}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n","import { type ComponentPropsWithoutRef, type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./AnimatedLogo.module.scss\";\n\ntype AnimatedLogoSegmentProps = Omit<ComponentPropsWithoutRef<\"g\">, \"children\"> & {\n\tchildren: ReactNode;\n\torder: number;\n};\n\n/**\n * Анимирует одну смысловую часть host-логотипа и сдвигает её pulse относительно предыдущих частей.\n * `order` задаётся с нуля в визуальной последовательности сегментов и преобразуется в шаг задержки 200 мс.\n */\nexport function AnimatedLogoSegment({ children, className, order, style, ...svgGroupProps }: AnimatedLogoSegmentProps) {\n\treturn (\n\t\t<g {...svgGroupProps} className={cn(styles.segment, className)} style={{ ...style, animationDelay: `${order * 200}ms` }}>\n\t\t\t{children}\n\t\t</g>\n\t);\n}\n","import { Placement } from \"@floating-ui/react\";\nimport { useCopyElementTextWithFeedback } from \"@ryuzaki13/react-foundation-lib/copy\";\nimport { CheckCheckIcon, CopyIcon } from \"lucide-react\";\n\nimport { FloatingPopover } from \"../popover\";\n\ninterface CopyTextWrapperProps {\n\tchildren: React.ReactNode;\n\tposition?: Placement;\n\tshowOnHover?: boolean;\n\tclassName?: string;\n}\n\nexport const CopyTextWrapper: React.FC<CopyTextWrapperProps> = ({ children, position = \"top\", showOnHover = true, className }) => {\n\tconst { containerRef, copyElementText, isCopied } = useCopyElementTextWithFeedback<HTMLSpanElement>();\n\n\treturn (\n\t\t<span ref={containerRef} className={className}>\n\t\t\t{children}\n\t\t\t<FloatingPopover openOnHover={showOnHover} placement={position} content={isCopied ? \"Скопировано!\" : \"Копировать текст\"}>\n\t\t\t\t<button onClick={copyElementText} aria-label={isCopied ? \"Скопировано!\" : \"Копировать текст\"}>\n\t\t\t\t\t{isCopied ? <CheckCheckIcon className=\"block statusSuccess\" /> : <CopyIcon className=\"block statusInfo\" />}\n\t\t\t\t</button>\n\t\t\t</FloatingPopover>\n\t\t</span>\n\t);\n};\n",".wrapper {\n\twidth: var(--control-height);\n\theight: var(--control-height);\n\tmargin: auto;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n","import { ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./IconWrapper.module.scss\";\n\ninterface IconWrapperProps {\n\tchildren: ReactNode;\n\tclassName?: string;\n}\n\nexport function IconWrapper({ className, children }: IconWrapperProps) {\n\treturn <div className={cn(styles.wrapper, className)}>{children}</div>;\n}\n",".componentLoader {\n\tmin-height: 10em;\n}\n","import { PropsWithChildren } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { FlexCenter } from \"../flex\";\nimport { Text, TextColor } from \"../text\";\n\ninterface MessageProps extends PropsWithChildren {\n\tclassName?: string;\n\tcolor?: TextColor;\n\tminHeight?: string | number;\n\tuppercase?: boolean;\n}\n\nexport const Message: React.FC<MessageProps> = ({ className, children, color = \"muted\", minHeight, uppercase = true }) => (\n\t<FlexCenter className={cn(\"paddingMd textCenter\", className)} minHeight={minHeight}>\n\t\t<Text as=\"div\" weight=\"bold\" color={color} uppercase={uppercase}>\n\t\t\t{children}\n\t\t</Text>\n\t</FlexCenter>\n);\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./LoadingMessage.module.scss\";\nimport { Message } from \"./Message\";\n\ntype LoadingMessageProps = {\n\tclassName?: string;\n\t/** Готовый брендовый знак, которым host-проект при необходимости дополняет сообщение о загрузке. */\n\tlogo?: ReactNode;\n\ttext?: string;\n};\n\nexport function LoadingMessage({ className, logo, text }: LoadingMessageProps) {\n\treturn (\n\t\t<Message className={cn(styles.componentLoader, logo ? undefined : \"skeletonLine\", className)}>\n\t\t\t{logo}\n\n\t\t\t{text || \"Загрузка...\"}\n\t\t</Message>\n\t);\n}\n","import { Suspense, useSyncExternalStore, type ComponentType, type ReactNode } from \"react\";\n\nimport { useLazyComponent } from \"@ryuzaki13/react-foundation-lib/hooks\";\n\nimport { LoadingMessage } from \"./LoadingMessage\";\n\ntype LazyDynamicComponentProps<T extends object> = {\n\timportFunc: () => Promise<Record<string, ComponentType<T>> | null>;\n\tcomponentName: string;\n\tcacheKey?: string;\n\tclientOnly?: boolean;\n\tfallback?: ReactNode;\n\tprops?: T;\n};\n\nconst subscribeClientOnlyMount = (onStoreChange: () => void) => {\n\tonStoreChange();\n\n\treturn () => undefined;\n};\n\nconst getClientSnapshot = () => true;\nconst getServerSnapshot = () => false;\n\n/**\n * Компонент ленивой загрузки динамически импортируемого React-компонента. Позволяет отложить загрузку тяжелых частей интерфейса до момента использования.\n */\nexport function LazyDynamicComponent<T extends object>({\n\tfallback,\n\timportFunc,\n\tcomponentName,\n\tclientOnly = false,\n\tcacheKey,\n\tprops\n}: LazyDynamicComponentProps<T>) {\n\tconst Component = useLazyComponent(importFunc, componentName, cacheKey);\n\tconst isClient = useSyncExternalStore(subscribeClientOnlyMount, getClientSnapshot, getServerSnapshot);\n\n\tconst fallbackNode = fallback ?? <LoadingMessage text=\"Ожидание компонента...\" />;\n\n\t// Client-only режим нужен для браузерных модулей, которые нельзя даже пытаться импортировать во время SSR.\n\tif (clientOnly && !isClient) return fallbackNode;\n\n\treturn (\n\t\t<Suspense fallback={fallbackNode}>\n\t\t\t{/* eslint-disable-next-line react-hooks/static-components */}\n\t\t\t<Component {...(props ?? ({} as T))} />\n\t\t</Suspense>\n\t);\n}\n","import React from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { PolymorphicComponent, PolymorphicComponentBaseProps } from \"../polymorphic\";\n\ntype SkeletonLineOwnProps<E extends React.ElementType = React.ElementType> = PolymorphicComponentBaseProps<E> & {\n\tclassName?: string;\n};\n\ntype SkeletonLineProps<E extends React.ElementType> = SkeletonLineOwnProps<E> &\n\tOmit<React.ComponentPropsWithRef<E>, keyof SkeletonLineOwnProps>;\n\nexport const SkeletonLine = <E extends React.ElementType>({ as, className, ...props }: SkeletonLineProps<E>) => {\n\tconst Component = as || \"div\";\n\n\treturn (\n\t\t<PolymorphicComponent\n\t\t\tas={Component as React.ElementType}\n\t\t\tclassName={cn(\"skeletonLine colorTransparent radiusSm\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n","import React from \"react\";\n\nimport { SkeletonLine } from \"./SkeletonLine\";\n\ninterface LazyValueProps {\n\tvalue: React.ReactNode;\n\tisLoading?: boolean;\n}\n\nexport function LazyValue({ value, isLoading }: LazyValueProps) {\n\treturn isLoading ? <SkeletonLine>Загрузка...</SkeletonLine> : (value ?? \"-\");\n}\n","import { Message } from \"./Message\";\n\ninterface NoDataProps {\n\tclassName?: string;\n\ttext?: string;\n\tminHeight?: string | number;\n}\n\nexport const NoData = ({ className, text, minHeight = \"5em\" }: NoDataProps) => {\n\treturn (\n\t\t<Message className={className} color=\"muted\" minHeight={minHeight}>\n\t\t\t{text || \"Нет данных\"}\n\t\t</Message>\n\t);\n};\n","import { PropsWithChildren } from \"react\";\n\nimport { Message } from \"./Message\";\n\ninterface NoticeProps extends PropsWithChildren {\n\tisError?: boolean;\n\tclassName?: string;\n}\n\nexport const Notice: React.FC<NoticeProps> = ({ className, isError, children }) => (\n\t<Message className={className} color={isError ? \"error\" : \"secondary\"}>\n\t\t{children}\n\t</Message>\n);\n",".oneStepScroller {\n\toverflow: hidden;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tmin-width: 0;\n}\n\n.ossViewport {\n\toverflow: hidden;\n\toutline: none;\n\tmin-width: 0;\n\tflex: 1 1 auto;\n}\n\n.ossScroller {\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\tgap: var(--space-sm);\n\talign-items: end;\n\toverflow-x: auto;\n\toverflow-y: hidden;\n\tscroll-behavior: smooth;\n\t-webkit-overflow-scrolling: touch;\n\tscrollbar-width: none; /* firefox */\n\n\t::-webkit-scrollbar {\n\t\theight: 0;\n\t}\n}\n\n.ossButton {\n\t// position: absolute;\n\ttop: 0;\n\tz-index: 10;\n\twidth: var(--control-height);\n\theight: 100%;\n\tflex: 0 0 var(--control-height);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\t// border: var(--border);\n\tborder-radius: var(--radius-sm);\n\tcolor: var(--content-2);\n\t// background-color: var(--surface-0);\n\t// opacity: 0.75;\n\n\ttransition-property: opacity, color;\n\ttransition-duration: var(--transition-fast);\n\n\t&:hover {\n\t\topacity: 1;\n\t\tcolor: var(--content-0);\n\t}\n\n\t&:disabled {\n\t\topacity: 0.5;\n\t\tpointer-events: none;\n\t}\n\n\t// &.prev {\n\t// \tleft: 0;\n\t// }\n\n\t// &.next {\n\t// \tright: 0;\n\t// }\n}\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { ChevronLeftIcon, ChevronRightIcon } from \"lucide-react\";\n\nimport styles from \"./OneStepScroller.module.scss\";\n\ninterface OneStepScrollerProps {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n\t/**\n\t * CSS-селектор элементов, которые считаются \"шагами\" скролла.\n\t * По умолчанию используются прямые потомки скроллера.\n\t */\n\titemSelector?: string;\n\t/**\n\t * Дополнительный внутренний отступ (px) при прокрутке к фокусируемому элементу.\n\t */\n\tscrollPadding?: number;\n\t/**\n\t * Плавная прокрутка для кнопок и авто-доводки до видимости.\n\t */\n\tsmooth?: boolean;\n}\n\nconst EDGE_EPSILON_PX = 1;\n\nfunction maxScrollLeft(scroller: HTMLElement) {\n\treturn Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n}\n\n/**\n * Горизонтальный скроллер \"по одному элементу\".\n *\n * Ожидает элементы фиксированной ширины (или близкой к фиксированной),\n * чтобы шаг скролла соответствовал ширине одного элемента.\n */\nexport const OneStepScroller: React.FC<OneStepScrollerProps> = ({\n\tchildren,\n\tclassName,\n\titemSelector,\n\tscrollPadding = 6,\n\tsmooth = true\n}) => {\n\tconst scrollerRef = useRef<HTMLDivElement | null>(null);\n\tconst rafIdRef = useRef<number | null>(null);\n\n\tconst [canScrollPrev, setCanScrollPrev] = useState(false);\n\tconst [canScrollNext, setCanScrollNext] = useState(false);\n\n\t/**\n\t * Получить список элементов-\"шагов\".\n\t *\n\t * Оптимизация: для дефолтного поведения используем `children` DOM-узла,\n\t * чтобы не выполнять `querySelectorAll` на каждый вызов.\n\t */\n\tconst getItems = useCallback((): HTMLElement[] => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return [];\n\n\t\tif (!itemSelector) {\n\t\t\treturn Array.from(scroller.children).filter((node): node is HTMLElement => node instanceof HTMLElement);\n\t\t}\n\n\t\treturn Array.from(scroller.querySelectorAll<HTMLElement>(itemSelector));\n\t}, [itemSelector]);\n\n\t/**\n\t * Найти \"элемент шага\" для произвольного target внутри скроллера.\n\t */\n\tconst findItemForTarget = useCallback(\n\t\t(target: HTMLElement): HTMLElement | null => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return null;\n\n\t\t\tif (itemSelector) {\n\t\t\t\tconst item = target.closest<HTMLElement>(itemSelector);\n\t\t\t\tif (item && scroller.contains(item)) return item;\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet node: HTMLElement | null = target;\n\t\t\twhile (node && node.parentElement && node.parentElement !== scroller) {\n\t\t\t\tnode = node.parentElement;\n\t\t\t}\n\n\t\t\tif (node && node.parentElement === scroller) return node;\n\t\t\treturn null;\n\t\t},\n\t\t[itemSelector]\n\t);\n\n\t/**\n\t * Обновить состояние кнопок \"назад/вперед\".\n\t * Состояние меняется только при реальном отличии, чтобы не триггерить\n\t * лишние перерисовки на каждом событии scroll.\n\t */\n\tconst updateScrollButtons = useCallback(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) {\n\t\t\tsetCanScrollPrev(false);\n\t\t\tsetCanScrollNext(false);\n\t\t\treturn;\n\t\t}\n\n\t\tconst maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n\t\tconst current = Math.max(0, Math.min(scroller.scrollLeft, maxScrollLeft));\n\n\t\tconst nextCanScrollPrev = current > EDGE_EPSILON_PX;\n\t\tconst nextCanScrollNext = current < maxScrollLeft - EDGE_EPSILON_PX;\n\n\t\tsetCanScrollPrev((prev) => (prev === nextCanScrollPrev ? prev : nextCanScrollPrev));\n\t\tsetCanScrollNext((prev) => (prev === nextCanScrollNext ? prev : nextCanScrollNext));\n\t}, []);\n\n\t/**\n\t * Запланировать обновление кнопок в следующий animation frame.\n\t * Это снижает частоту вычислений при интенсивном scroll/resize.\n\t */\n\tconst scheduleUpdateScrollButtons = useCallback(() => {\n\t\tif (rafIdRef.current !== null) return;\n\n\t\trafIdRef.current = requestAnimationFrame(() => {\n\t\t\trafIdRef.current = null;\n\t\t\tupdateScrollButtons();\n\t\t});\n\t}, [updateScrollButtons]);\n\n\t/**\n\t * Прокрутка на N элементов (N может быть отрицательным).\n\t */\n\tconst scrollByItems = useCallback(\n\t\t(count: number) => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return;\n\n\t\t\tconst firstItem = getItems()[0];\n\t\t\tif (!firstItem) return;\n\n\t\t\tconst step = firstItem.getBoundingClientRect().width;\n\t\t\tif (!step) return;\n\n\t\t\tconst delta = Math.round(count * step);\n\t\t\tconst maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n\t\t\tconst target = Math.max(0, Math.min(scroller.scrollLeft + delta, maxScrollLeft));\n\n\t\t\tscroller.scrollTo({\n\t\t\t\tleft: target,\n\t\t\t\tbehavior: smooth ? \"smooth\" : \"auto\"\n\t\t\t});\n\t\t},\n\t\t[getItems, smooth]\n\t);\n\n\t/**\n\t * Гарантировать полную видимость элемента в пределах viewport скроллера.\n\t */\n\tconst ensureFullyVisible = useCallback(\n\t\t(el: HTMLElement) => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return;\n\n\t\t\tconst scrollerRect = scroller.getBoundingClientRect();\n\t\t\tconst elementRect = el.getBoundingClientRect();\n\n\t\t\tconst elementLeft = elementRect.left - scrollerRect.left + scroller.scrollLeft;\n\t\t\tconst elementRight = elementLeft + elementRect.width;\n\n\t\t\tconst visibleLeft = scroller.scrollLeft;\n\t\t\tconst visibleRight = scroller.scrollLeft + scroller.clientWidth;\n\n\t\t\tif (elementLeft >= visibleLeft + EDGE_EPSILON_PX && elementRight <= visibleRight - EDGE_EPSILON_PX) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet targetScrollLeft = scroller.scrollLeft;\n\t\t\tif (elementLeft < visibleLeft) {\n\t\t\t\ttargetScrollLeft = Math.max(0, elementLeft - scrollPadding);\n\t\t\t} else if (elementRight > visibleRight) {\n\t\t\t\ttargetScrollLeft = Math.min(maxScrollLeft(scroller), elementRight - scroller.clientWidth + scrollPadding);\n\t\t\t}\n\n\t\t\tscroller.scrollTo({\n\t\t\t\tleft: Math.round(targetScrollLeft),\n\t\t\t\tbehavior: smooth ? \"smooth\" : \"auto\"\n\t\t\t});\n\t\t},\n\t\t[scrollPadding, smooth]\n\t);\n\n\tuseEffect(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return;\n\n\t\tconst handleFocusIn = (event: FocusEvent) => {\n\t\t\tconst target = event.target;\n\t\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\t\tconst item = findItemForTarget(target);\n\t\t\tif (item) ensureFullyVisible(item);\n\t\t};\n\n\t\tscroller.addEventListener(\"focusin\", handleFocusIn);\n\t\treturn () => scroller.removeEventListener(\"focusin\", handleFocusIn);\n\t}, [ensureFullyVisible, findItemForTarget]);\n\n\t/**\n\t * Наблюдаем только за размером скроллера и изменением его DOM-структуры.\n\t * Это дешевле, чем подписка ResizeObserver на каждый элемент + IntersectionObserver.\n\t */\n\tuseEffect(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return;\n\n\t\tconst onScroll = () => scheduleUpdateScrollButtons();\n\t\tscroller.addEventListener(\"scroll\", onScroll, { passive: true });\n\n\t\tlet resizeObserver: ResizeObserver | null = null;\n\t\tif (typeof ResizeObserver !== \"undefined\") {\n\t\t\tresizeObserver = new ResizeObserver(scheduleUpdateScrollButtons);\n\t\t\tresizeObserver.observe(scroller);\n\t\t}\n\n\t\tlet mutationObserver: MutationObserver | null = null;\n\t\tif (typeof MutationObserver !== \"undefined\") {\n\t\t\tmutationObserver = new MutationObserver(scheduleUpdateScrollButtons);\n\t\t\tmutationObserver.observe(scroller, {\n\t\t\t\tchildList: true,\n\t\t\t\tsubtree: false\n\t\t\t});\n\t\t}\n\n\t\tscheduleUpdateScrollButtons();\n\n\t\treturn () => {\n\t\t\tscroller.removeEventListener(\"scroll\", onScroll);\n\t\t\tresizeObserver?.disconnect();\n\t\t\tmutationObserver?.disconnect();\n\n\t\t\tif (rafIdRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafIdRef.current);\n\t\t\t\trafIdRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [scheduleUpdateScrollButtons]);\n\n\t/**\n\t * При изменении children просим пересчитать видимость кнопок.\n\t */\n\tuseEffect(() => {\n\t\tscheduleUpdateScrollButtons();\n\t}, [children, scheduleUpdateScrollButtons]);\n\n\tconst handlePrev = () => scrollByItems(-1);\n\tconst handleNext = () => scrollByItems(1);\n\n\t/**\n\t * Клавиатурная доступность: стрелки влево/вправо двигают на один шаг.\n\t */\n\tconst onWrapperKeyDown = (e: React.KeyboardEvent) => {\n\t\tif (e.key === \"ArrowLeft\") {\n\t\t\te.preventDefault();\n\t\t\thandlePrev();\n\t\t} else if (e.key === \"ArrowRight\") {\n\t\t\te.preventDefault();\n\t\t\thandleNext();\n\t\t}\n\t};\n\n\tconst hasScroll = canScrollPrev || canScrollNext;\n\n\treturn (\n\t\t<div className={cn(styles.oneStepScroller, className)} style={{ position: \"relative\" }}>\n\t\t\t{hasScroll && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Прокрутить шаг влево\"\n\t\t\t\t\tclassName={styles.ossButton}\n\t\t\t\t\tonClick={handlePrev}\n\t\t\t\t\tdisabled={!canScrollPrev}>\n\t\t\t\t\t<ChevronLeftIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\n\t\t\t<div className={styles.ossViewport} onKeyDown={onWrapperKeyDown} role=\"group\" aria-label=\"Элементы прокрутки\">\n\t\t\t\t<div className={styles.ossScroller} ref={scrollerRef} aria-live=\"polite\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{hasScroll && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Прокрутить шаг вправо\"\n\t\t\t\t\tclassName={styles.ossButton}\n\t\t\t\t\tonClick={handleNext}\n\t\t\t\t\tdisabled={!canScrollNext}>\n\t\t\t\t\t<ChevronRightIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n};\n","import { forwardRef, PropsWithChildren } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\ninterface ScrollableProps extends PropsWithChildren {\n\tclassName?: string;\n\theight?: string | number;\n\tstable?: boolean;\n\toverscroll?: boolean;\n}\n\nexport const Scrollable = forwardRef<HTMLDivElement, ScrollableProps>(({ children, height, stable, overscroll, className }, ref) => {\n\treturn (\n\t\t<div ref={ref} className={cn(\"scrollable\", stable && \"stable\", overscroll && \"overscroll\", className)} style={{ height }}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\n\ninterface ScrollableBlockProps extends ScrollableProps {\n\tblockClassName?: string;\n}\n\nexport const ScrollableBlock = forwardRef<HTMLDivElement, ScrollableBlockProps>(({ blockClassName, ...props }, ref) => {\n\treturn (\n\t\t<div className={cn(blockClassName, \"overflowHidden w100 h100\")}>\n\t\t\t<Scrollable ref={ref} {...props} />\n\t\t</div>\n\t);\n});\n",".stateWrapper {\n\ttext-decoration: none;\n\tcolor: inherit;\n\tdisplay: block;\n\n\t// border: var(--border-width) solid var(--state-border-color, transparent);\n\tborder-left-style: solid;\n\tborder-left-color: var(--state-border-color, transparent);\n\tborder-left-width: 0.0625em; // 1px\n\tpadding-left: 0.25em; // 4px + 1px border\n\n\t&.status {\n\t\tborder-left-width: 0.3125em; // 5px\n\t\tpadding-left: 0;\n\n\t\t&.information {\n\t\t\tborder-left-color: var(--status-info-fill);\n\t\t}\n\n\t\t&.success {\n\t\t\tborder-left-color: var(--status-success-fill);\n\t\t}\n\n\t\t&.warning {\n\t\t\tborder-left-color: var(--status-warning-fill);\n\t\t}\n\n\t\t&.error {\n\t\t\tborder-left-color: var(--status-error-fill);\n\t\t}\n\t}\n}\n\n.state {\n\t&.information {\n\t\tcolor: var(--status-info-text);\n\n\t\tfill: var(--status-info-fill);\n\t\tstroke: var(--status-info-on-fill);\n\t}\n\n\t&.success {\n\t\tcolor: var(--status-success-text);\n\n\t\tfill: var(--status-success-fill);\n\t\tstroke: var(--status-success-on-fill);\n\t}\n\n\t&.warning {\n\t\tcolor: var(--status-warning-text);\n\n\t\tfill: var(--status-warning-fill);\n\t\tstroke: var(--status-warning-on-fill);\n\t\tstroke-width: 2px;\n\t}\n\n\t&.error {\n\t\tcolor: var(--status-error-text);\n\n\t\tfill: var(--status-error-fill);\n\t\tstroke: var(--status-error-on-fill);\n\t}\n}\n","import React from \"react\";\n\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { CircleAlertIcon, CircleCheckIcon, CircleXIcon, InfoIcon } from \"lucide-react\";\n\nimport styles from \"./State.module.scss\";\n\ninterface StateIconProps {\n\tstate: State;\n\ttext: string;\n\tclassName?: string;\n}\n\nexport const StateIcon: React.FC<StateIconProps> = ({ state = \"none\", text, className }) => {\n\tconst renderIcon = () => {\n\t\tswitch (state) {\n\t\t\tcase \"error\":\n\t\t\t\treturn <ErrorIcon />;\n\t\t\tcase \"warning\":\n\t\t\t\treturn <WarningIcon />;\n\t\t\tcase \"success\":\n\t\t\t\treturn <SuccessIcon />;\n\t\t\tcase \"information\":\n\t\t\t\treturn <InformationIcon />;\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t};\n\n\treturn (\n\t\t<div className={cn(\"flexCenter gapSm\", className)}>\n\t\t\t{renderIcon()}\n\t\t\t{text}\n\t\t</div>\n\t);\n};\n\ninterface RenderStateIconProps {\n\tstate?: State;\n}\n\nexport const RenderStateIcon: React.FC<RenderStateIconProps> = ({ state }) => {\n\tswitch (state) {\n\t\tcase \"error\":\n\t\t\treturn <ErrorIcon />;\n\t\tcase \"warning\":\n\t\t\treturn <WarningIcon />;\n\t\tcase \"success\":\n\t\t\treturn <SuccessIcon />;\n\t\tcase \"information\":\n\t\t\treturn <InformationIcon />;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const ErrorIcon = () => {\n\treturn <CircleXIcon className={cn(styles.state, styles.error)} />;\n};\nexport const WarningIcon = () => {\n\treturn <CircleAlertIcon className={cn(styles.state, styles.warning)} />;\n};\nexport const SuccessIcon = () => {\n\treturn <CircleCheckIcon className={cn(styles.state, styles.success)} />;\n};\nexport const InformationIcon = () => {\n\treturn <InfoIcon className={cn(styles.state, styles.information)} />;\n};\n","import React from \"react\";\n\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { PolymorphicComponent, PolymorphicComponentBaseProps } from \"../polymorphic\";\n\nimport styles from \"./State.module.scss\";\n\ntype StateWrapperOwnProps<E extends React.ElementType = React.ElementType> = PolymorphicComponentBaseProps<E> & {\n\tstate?: State;\n\tclassName?: string;\n};\n\ntype StateWrapperProps<E extends React.ElementType> = StateWrapperOwnProps<E> &\n\tOmit<React.ComponentPropsWithRef<E>, keyof StateWrapperOwnProps>;\n\nexport function StateWrapper<E extends React.ElementType>({ as, state, className, ...props }: StateWrapperProps<E>) {\n\tconst status = state?.toLowerCase() ?? \"none\";\n\tconst statusClass = styles[status as keyof typeof styles];\n\tconst isStatused = status && status !== \"none\";\n\n\tconst Component = as || \"div\";\n\n\treturn (\n\t\t<PolymorphicComponent\n\t\t\tas={Component as React.ElementType}\n\t\t\tclassName={cn(styles.stateWrapper, isStatused && styles.status, statusClass, className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"misc-BYxxlJz6.js","names":[],"sources":["../../src/misc/AnimatedLogo.module.scss","../../src/misc/AnimatedLogo.tsx","../../src/misc/AnimatedLogoSegment.tsx","../../src/misc/CopyTextWrapper.tsx","../../src/misc/IconWrapper.module.scss","../../src/misc/IconWrapper.tsx","../../src/misc/LoadingMessage.module.scss","../../src/misc/Message.tsx","../../src/misc/LoadingMessage.tsx","../../src/misc/LazyDynamicComponent.tsx","../../src/misc/SkeletonLine.tsx","../../src/misc/LazyValue.tsx","../../src/misc/NoData.tsx","../../src/misc/Notice.tsx","../../src/misc/OneStepScroller.module.scss","../../src/misc/OneStepScroller.tsx","../../src/misc/Scrollable.tsx","../../src/misc/State.module.scss","../../src/misc/StateIcon.tsx","../../src/misc/StateWrapper.tsx"],"sourcesContent":[".logo {\n\tsvg {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\theight: auto;\n\t}\n}\n\n.segment {\n\topacity: 0.2;\n\tanimation: pulseSteps 2s ease-in-out infinite;\n}\n\n@keyframes pulseSteps {\n\t0% {\n\t\topacity: 0.2;\n\t}\n\n\t35%,\n\t55% {\n\t\topacity: 1;\n\t}\n\n\t100% {\n\t\topacity: 0.2;\n\t}\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.segment {\n\t\tanimation: none;\n\t\topacity: 1;\n\t}\n}\n","import { type ComponentPropsWithoutRef, type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./AnimatedLogo.module.scss\";\n\ntype AnimatedLogoProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n\tchildren: ReactNode;\n};\n\n/**\n * Контейнер анимированного логотипа без брендовой SVG-разметки.\n * Host-проект передаёт собственный `svg`, а его визуальные части оборачивает в `AnimatedLogoSegment`.\n */\nexport function AnimatedLogo({ children, className, ...htmlProps }: AnimatedLogoProps) {\n\treturn (\n\t\t<div {...htmlProps} className={cn(styles.logo, className)}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n","import { type ComponentPropsWithoutRef, type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./AnimatedLogo.module.scss\";\n\ntype AnimatedLogoSegmentProps = Omit<ComponentPropsWithoutRef<\"g\">, \"children\"> & {\n\tchildren: ReactNode;\n\torder: number;\n};\n\n/**\n * Анимирует одну смысловую часть host-логотипа и сдвигает её pulse относительно предыдущих частей.\n * `order` задаётся с нуля в визуальной последовательности сегментов и преобразуется в шаг задержки 200 мс.\n */\nexport function AnimatedLogoSegment({ children, className, order, style, ...svgGroupProps }: AnimatedLogoSegmentProps) {\n\treturn (\n\t\t<g {...svgGroupProps} className={cn(styles.segment, className)} style={{ ...style, animationDelay: `${order * 200}ms` }}>\n\t\t\t{children}\n\t\t</g>\n\t);\n}\n","import { Placement } from \"@floating-ui/react\";\nimport { useCopyElementTextWithFeedback } from \"@ryuzaki13/react-foundation-lib/copy\";\nimport { CheckCheckIcon, CopyIcon } from \"lucide-react\";\n\nimport { FloatingPopover } from \"../popover\";\n\ninterface CopyTextWrapperProps {\n\tchildren: React.ReactNode;\n\tposition?: Placement;\n\tshowOnHover?: boolean;\n\tclassName?: string;\n}\n\nexport const CopyTextWrapper: React.FC<CopyTextWrapperProps> = ({ children, position = \"top\", showOnHover = true, className }) => {\n\tconst { containerRef, copyElementText, isCopied } = useCopyElementTextWithFeedback<HTMLSpanElement>();\n\n\treturn (\n\t\t<span ref={containerRef} className={className}>\n\t\t\t{children}\n\t\t\t<FloatingPopover openOnHover={showOnHover} placement={position} content={isCopied ? \"Скопировано!\" : \"Копировать текст\"}>\n\t\t\t\t<button onClick={copyElementText} aria-label={isCopied ? \"Скопировано!\" : \"Копировать текст\"}>\n\t\t\t\t\t{isCopied ? <CheckCheckIcon className=\"block statusSuccess\" /> : <CopyIcon className=\"block statusInfo\" />}\n\t\t\t\t</button>\n\t\t\t</FloatingPopover>\n\t\t</span>\n\t);\n};\n",".wrapper {\n\twidth: var(--control-height);\n\theight: var(--control-height);\n\tmargin: auto;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n","import { ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./IconWrapper.module.scss\";\n\ninterface IconWrapperProps {\n\tchildren: ReactNode;\n\tclassName?: string;\n}\n\nexport function IconWrapper({ className, children }: IconWrapperProps) {\n\treturn <div className={cn(styles.wrapper, className)}>{children}</div>;\n}\n",".componentLoader {\n\tmin-height: 10em;\n}\n","import { PropsWithChildren } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { FlexCenter } from \"../flex\";\nimport { Text, TextColor } from \"../text\";\n\ninterface MessageProps extends PropsWithChildren {\n\tclassName?: string;\n\tcolor?: TextColor;\n\tminHeight?: string | number;\n\tuppercase?: boolean;\n}\n\nexport const Message: React.FC<MessageProps> = ({ className, children, color = \"muted\", minHeight, uppercase = true }) => (\n\t<FlexCenter className={cn(\"paddingMd textCenter\", className)} minHeight={minHeight}>\n\t\t<Text as=\"div\" weight=\"bold\" color={color} uppercase={uppercase}>\n\t\t\t{children}\n\t\t</Text>\n\t</FlexCenter>\n);\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport styles from \"./LoadingMessage.module.scss\";\nimport { Message } from \"./Message\";\n\ntype LoadingMessageProps = {\n\tclassName?: string;\n\t/** Готовый брендовый знак, которым host-проект при необходимости дополняет сообщение о загрузке. */\n\tlogo?: ReactNode;\n\ttext?: string;\n};\n\nexport function LoadingMessage({ className, logo, text }: LoadingMessageProps) {\n\treturn (\n\t\t<Message className={cn(styles.componentLoader, logo ? undefined : \"skeletonLine\", className)}>\n\t\t\t{logo}\n\n\t\t\t{text || \"Загрузка...\"}\n\t\t</Message>\n\t);\n}\n","import { Suspense, useSyncExternalStore, type ComponentType, type ReactNode } from \"react\";\n\nimport { useLazyComponent } from \"@ryuzaki13/react-foundation-lib/hooks\";\n\nimport { LoadingMessage } from \"./LoadingMessage\";\n\ntype LazyDynamicComponentProps<T extends object> = {\n\timportFunc: () => Promise<Record<string, ComponentType<T>> | null>;\n\tcomponentName: string;\n\tcacheKey?: string;\n\tclientOnly?: boolean;\n\tfallback?: ReactNode;\n\tprops?: T;\n};\n\nconst subscribeClientOnlyMount = (onStoreChange: () => void) => {\n\tonStoreChange();\n\n\treturn () => undefined;\n};\n\nconst getClientSnapshot = () => true;\nconst getServerSnapshot = () => false;\n\n/**\n * Компонент ленивой загрузки динамически импортируемого React-компонента. Позволяет отложить загрузку тяжелых частей интерфейса до момента использования.\n */\nexport function LazyDynamicComponent<T extends object>({\n\tfallback,\n\timportFunc,\n\tcomponentName,\n\tclientOnly = false,\n\tcacheKey,\n\tprops\n}: LazyDynamicComponentProps<T>) {\n\tconst Component = useLazyComponent(importFunc, componentName, cacheKey);\n\tconst isClient = useSyncExternalStore(subscribeClientOnlyMount, getClientSnapshot, getServerSnapshot);\n\n\tconst fallbackNode = fallback ?? <LoadingMessage text=\"Ожидание компонента...\" />;\n\n\t// Client-only режим нужен для браузерных модулей, которые нельзя даже пытаться импортировать во время SSR.\n\tif (clientOnly && !isClient) return fallbackNode;\n\n\treturn (\n\t\t<Suspense fallback={fallbackNode}>\n\t\t\t{/* eslint-disable-next-line react-hooks/static-components */}\n\t\t\t<Component {...(props ?? ({} as T))} />\n\t\t</Suspense>\n\t);\n}\n","import React from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { PolymorphicComponent, PolymorphicComponentBaseProps } from \"../polymorphic\";\n\ntype SkeletonLineOwnProps<E extends React.ElementType = React.ElementType> = PolymorphicComponentBaseProps<E> & {\n\tclassName?: string;\n};\n\ntype SkeletonLineProps<E extends React.ElementType> = SkeletonLineOwnProps<E> &\n\tOmit<React.ComponentPropsWithRef<E>, keyof SkeletonLineOwnProps>;\n\nexport const SkeletonLine = <E extends React.ElementType>({ as, className, ...props }: SkeletonLineProps<E>) => {\n\tconst Component = as || \"div\";\n\n\treturn (\n\t\t<PolymorphicComponent\n\t\t\tas={Component as React.ElementType}\n\t\t\tclassName={cn(\"skeletonLine colorTransparent radiusSm\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n","import React from \"react\";\n\nimport { SkeletonLine } from \"./SkeletonLine\";\n\ninterface LazyValueProps {\n\tvalue: React.ReactNode;\n\tisLoading?: boolean;\n}\n\nexport function LazyValue({ value, isLoading }: LazyValueProps) {\n\treturn isLoading ? <SkeletonLine>Загрузка...</SkeletonLine> : (value ?? \"-\");\n}\n","import { Message } from \"./Message\";\n\ninterface NoDataProps {\n\tclassName?: string;\n\ttext?: string;\n\tminHeight?: string | number;\n}\n\nexport const NoData = ({ className, text, minHeight = \"5em\" }: NoDataProps) => {\n\treturn (\n\t\t<Message className={className} color=\"muted\" minHeight={minHeight}>\n\t\t\t{text || \"Нет данных\"}\n\t\t</Message>\n\t);\n};\n","import { PropsWithChildren } from \"react\";\n\nimport { Message } from \"./Message\";\n\ninterface NoticeProps extends PropsWithChildren {\n\tisError?: boolean;\n\tclassName?: string;\n}\n\nexport const Notice: React.FC<NoticeProps> = ({ className, isError, children }) => (\n\t<Message className={className} color={isError ? \"error\" : \"secondary\"}>\n\t\t{children}\n\t</Message>\n);\n",".oneStepScroller {\n\toverflow: hidden;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tmin-width: 0;\n}\n\n.ossViewport {\n\toverflow: hidden;\n\toutline: none;\n\tmin-width: 0;\n\tflex: 1 1 auto;\n}\n\n.ossScroller {\n\tdisplay: flex;\n\tflex-wrap: nowrap;\n\tgap: var(--space-sm);\n\talign-items: end;\n\toverflow-x: auto;\n\toverflow-y: hidden;\n\tscroll-behavior: smooth;\n\t-webkit-overflow-scrolling: touch;\n\tscrollbar-width: none; /* firefox */\n\n\t::-webkit-scrollbar {\n\t\theight: 0;\n\t}\n}\n\n.ossButton {\n\t// position: absolute;\n\ttop: 0;\n\tz-index: 10;\n\twidth: var(--control-height);\n\theight: 100%;\n\tflex: 0 0 var(--control-height);\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\t// border: var(--border);\n\tborder-radius: var(--radius-sm);\n\tcolor: var(--content-2);\n\t// background-color: var(--surface-0);\n\t// opacity: 0.75;\n\n\ttransition-property: opacity, color;\n\ttransition-duration: var(--transition-fast);\n\n\t&:hover {\n\t\topacity: 1;\n\t\tcolor: var(--content-0);\n\t}\n\n\t&:disabled {\n\t\topacity: 0.5;\n\t\tpointer-events: none;\n\t}\n\n\t// &.prev {\n\t// \tleft: 0;\n\t// }\n\n\t// &.next {\n\t// \tright: 0;\n\t// }\n}\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { ChevronLeftIcon, ChevronRightIcon } from \"lucide-react\";\n\nimport styles from \"./OneStepScroller.module.scss\";\n\ninterface OneStepScrollerProps {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n\t/**\n\t * CSS-селектор элементов, которые считаются \"шагами\" скролла.\n\t * По умолчанию используются прямые потомки скроллера.\n\t */\n\titemSelector?: string;\n\t/**\n\t * Дополнительный внутренний отступ (px) при прокрутке к фокусируемому элементу.\n\t */\n\tscrollPadding?: number;\n\t/**\n\t * Плавная прокрутка для кнопок и авто-доводки до видимости.\n\t */\n\tsmooth?: boolean;\n}\n\nconst EDGE_EPSILON_PX = 1;\n\nfunction maxScrollLeft(scroller: HTMLElement) {\n\treturn Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n}\n\n/**\n * Горизонтальный скроллер \"по одному элементу\".\n *\n * Ожидает элементы фиксированной ширины (или близкой к фиксированной),\n * чтобы шаг скролла соответствовал ширине одного элемента.\n */\nexport const OneStepScroller: React.FC<OneStepScrollerProps> = ({\n\tchildren,\n\tclassName,\n\titemSelector,\n\tscrollPadding = 6,\n\tsmooth = true\n}) => {\n\tconst scrollerRef = useRef<HTMLDivElement | null>(null);\n\tconst rafIdRef = useRef<number | null>(null);\n\n\tconst [canScrollPrev, setCanScrollPrev] = useState(false);\n\tconst [canScrollNext, setCanScrollNext] = useState(false);\n\n\t/**\n\t * Получить список элементов-\"шагов\".\n\t *\n\t * Оптимизация: для дефолтного поведения используем `children` DOM-узла,\n\t * чтобы не выполнять `querySelectorAll` на каждый вызов.\n\t */\n\tconst getItems = useCallback((): HTMLElement[] => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return [];\n\n\t\tif (!itemSelector) {\n\t\t\treturn Array.from(scroller.children).filter((node): node is HTMLElement => node instanceof HTMLElement);\n\t\t}\n\n\t\treturn Array.from(scroller.querySelectorAll<HTMLElement>(itemSelector));\n\t}, [itemSelector]);\n\n\t/**\n\t * Найти \"элемент шага\" для произвольного target внутри скроллера.\n\t */\n\tconst findItemForTarget = useCallback(\n\t\t(target: HTMLElement): HTMLElement | null => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return null;\n\n\t\t\tif (itemSelector) {\n\t\t\t\tconst item = target.closest<HTMLElement>(itemSelector);\n\t\t\t\tif (item && scroller.contains(item)) return item;\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet node: HTMLElement | null = target;\n\t\t\twhile (node && node.parentElement && node.parentElement !== scroller) {\n\t\t\t\tnode = node.parentElement;\n\t\t\t}\n\n\t\t\tif (node && node.parentElement === scroller) return node;\n\t\t\treturn null;\n\t\t},\n\t\t[itemSelector]\n\t);\n\n\t/**\n\t * Обновить состояние кнопок \"назад/вперед\".\n\t * Состояние меняется только при реальном отличии, чтобы не триггерить\n\t * лишние перерисовки на каждом событии scroll.\n\t */\n\tconst updateScrollButtons = useCallback(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) {\n\t\t\tsetCanScrollPrev(false);\n\t\t\tsetCanScrollNext(false);\n\t\t\treturn;\n\t\t}\n\n\t\tconst maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n\t\tconst current = Math.max(0, Math.min(scroller.scrollLeft, maxScrollLeft));\n\n\t\tconst nextCanScrollPrev = current > EDGE_EPSILON_PX;\n\t\tconst nextCanScrollNext = current < maxScrollLeft - EDGE_EPSILON_PX;\n\n\t\tsetCanScrollPrev((prev) => (prev === nextCanScrollPrev ? prev : nextCanScrollPrev));\n\t\tsetCanScrollNext((prev) => (prev === nextCanScrollNext ? prev : nextCanScrollNext));\n\t}, []);\n\n\t/**\n\t * Запланировать обновление кнопок в следующий animation frame.\n\t * Это снижает частоту вычислений при интенсивном scroll/resize.\n\t */\n\tconst scheduleUpdateScrollButtons = useCallback(() => {\n\t\tif (rafIdRef.current !== null) return;\n\n\t\trafIdRef.current = requestAnimationFrame(() => {\n\t\t\trafIdRef.current = null;\n\t\t\tupdateScrollButtons();\n\t\t});\n\t}, [updateScrollButtons]);\n\n\t/**\n\t * Прокрутка на N элементов (N может быть отрицательным).\n\t */\n\tconst scrollByItems = useCallback(\n\t\t(count: number) => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return;\n\n\t\t\tconst firstItem = getItems()[0];\n\t\t\tif (!firstItem) return;\n\n\t\t\tconst step = firstItem.getBoundingClientRect().width;\n\t\t\tif (!step) return;\n\n\t\t\tconst delta = Math.round(count * step);\n\t\t\tconst maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n\t\t\tconst target = Math.max(0, Math.min(scroller.scrollLeft + delta, maxScrollLeft));\n\n\t\t\tscroller.scrollTo({\n\t\t\t\tleft: target,\n\t\t\t\tbehavior: smooth ? \"smooth\" : \"auto\"\n\t\t\t});\n\t\t},\n\t\t[getItems, smooth]\n\t);\n\n\t/**\n\t * Гарантировать полную видимость элемента в пределах viewport скроллера.\n\t */\n\tconst ensureFullyVisible = useCallback(\n\t\t(el: HTMLElement) => {\n\t\t\tconst scroller = scrollerRef.current;\n\t\t\tif (!scroller) return;\n\n\t\t\tconst scrollerRect = scroller.getBoundingClientRect();\n\t\t\tconst elementRect = el.getBoundingClientRect();\n\n\t\t\tconst elementLeft = elementRect.left - scrollerRect.left + scroller.scrollLeft;\n\t\t\tconst elementRight = elementLeft + elementRect.width;\n\n\t\t\tconst visibleLeft = scroller.scrollLeft;\n\t\t\tconst visibleRight = scroller.scrollLeft + scroller.clientWidth;\n\n\t\t\tif (elementLeft >= visibleLeft + EDGE_EPSILON_PX && elementRight <= visibleRight - EDGE_EPSILON_PX) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet targetScrollLeft = scroller.scrollLeft;\n\t\t\tif (elementLeft < visibleLeft) {\n\t\t\t\ttargetScrollLeft = Math.max(0, elementLeft - scrollPadding);\n\t\t\t} else if (elementRight > visibleRight) {\n\t\t\t\ttargetScrollLeft = Math.min(maxScrollLeft(scroller), elementRight - scroller.clientWidth + scrollPadding);\n\t\t\t}\n\n\t\t\tscroller.scrollTo({\n\t\t\t\tleft: Math.round(targetScrollLeft),\n\t\t\t\tbehavior: smooth ? \"smooth\" : \"auto\"\n\t\t\t});\n\t\t},\n\t\t[scrollPadding, smooth]\n\t);\n\n\tuseEffect(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return;\n\n\t\tconst handleFocusIn = (event: FocusEvent) => {\n\t\t\tconst target = event.target;\n\t\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\t\tconst item = findItemForTarget(target);\n\t\t\tif (item) ensureFullyVisible(item);\n\t\t};\n\n\t\tscroller.addEventListener(\"focusin\", handleFocusIn);\n\t\treturn () => scroller.removeEventListener(\"focusin\", handleFocusIn);\n\t}, [ensureFullyVisible, findItemForTarget]);\n\n\t/**\n\t * Наблюдаем только за размером скроллера и изменением его DOM-структуры.\n\t * Это дешевле, чем подписка ResizeObserver на каждый элемент + IntersectionObserver.\n\t */\n\tuseEffect(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) return;\n\n\t\tconst onScroll = () => scheduleUpdateScrollButtons();\n\t\tscroller.addEventListener(\"scroll\", onScroll, { passive: true });\n\n\t\tlet resizeObserver: ResizeObserver | null = null;\n\t\tif (typeof ResizeObserver !== \"undefined\") {\n\t\t\tresizeObserver = new ResizeObserver(scheduleUpdateScrollButtons);\n\t\t\tresizeObserver.observe(scroller);\n\t\t}\n\n\t\tlet mutationObserver: MutationObserver | null = null;\n\t\tif (typeof MutationObserver !== \"undefined\") {\n\t\t\tmutationObserver = new MutationObserver(scheduleUpdateScrollButtons);\n\t\t\tmutationObserver.observe(scroller, {\n\t\t\t\tchildList: true,\n\t\t\t\tsubtree: false\n\t\t\t});\n\t\t}\n\n\t\tscheduleUpdateScrollButtons();\n\n\t\treturn () => {\n\t\t\tscroller.removeEventListener(\"scroll\", onScroll);\n\t\t\tresizeObserver?.disconnect();\n\t\t\tmutationObserver?.disconnect();\n\n\t\t\tif (rafIdRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafIdRef.current);\n\t\t\t\trafIdRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [scheduleUpdateScrollButtons]);\n\n\t/**\n\t * При изменении children просим пересчитать видимость кнопок.\n\t */\n\tuseEffect(() => {\n\t\tscheduleUpdateScrollButtons();\n\t}, [children, scheduleUpdateScrollButtons]);\n\n\tconst handlePrev = () => scrollByItems(-1);\n\tconst handleNext = () => scrollByItems(1);\n\n\t/**\n\t * Клавиатурная доступность: стрелки влево/вправо двигают на один шаг.\n\t */\n\tconst onWrapperKeyDown = (e: React.KeyboardEvent) => {\n\t\tif (e.key === \"ArrowLeft\") {\n\t\t\te.preventDefault();\n\t\t\thandlePrev();\n\t\t} else if (e.key === \"ArrowRight\") {\n\t\t\te.preventDefault();\n\t\t\thandleNext();\n\t\t}\n\t};\n\n\tconst hasScroll = canScrollPrev || canScrollNext;\n\n\treturn (\n\t\t<div className={cn(styles.oneStepScroller, className)} style={{ position: \"relative\" }}>\n\t\t\t{hasScroll && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Прокрутить шаг влево\"\n\t\t\t\t\tclassName={styles.ossButton}\n\t\t\t\t\tonClick={handlePrev}\n\t\t\t\t\tdisabled={!canScrollPrev}>\n\t\t\t\t\t<ChevronLeftIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\n\t\t\t<div className={styles.ossViewport} onKeyDown={onWrapperKeyDown} role=\"group\" aria-label=\"Элементы прокрутки\">\n\t\t\t\t<div className={styles.ossScroller} ref={scrollerRef} aria-live=\"polite\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{hasScroll && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Прокрутить шаг вправо\"\n\t\t\t\t\tclassName={styles.ossButton}\n\t\t\t\t\tonClick={handleNext}\n\t\t\t\t\tdisabled={!canScrollNext}>\n\t\t\t\t\t<ChevronRightIcon />\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n};\n","import { forwardRef, PropsWithChildren } from \"react\";\n\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\ninterface ScrollableProps extends PropsWithChildren {\n\tclassName?: string;\n\theight?: string | number;\n\tstable?: boolean;\n\toverscroll?: boolean;\n}\n\nexport const Scrollable = forwardRef<HTMLDivElement, ScrollableProps>(({ children, height, stable, overscroll, className }, ref) => {\n\treturn (\n\t\t<div ref={ref} className={cn(\"scrollable\", stable && \"stable\", overscroll && \"overscroll\", className)} style={{ height }}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\n\ninterface ScrollableBlockProps extends ScrollableProps {\n\tblockClassName?: string;\n}\n\nexport const ScrollableBlock = forwardRef<HTMLDivElement, ScrollableBlockProps>(({ blockClassName, ...props }, ref) => {\n\treturn (\n\t\t<div className={cn(blockClassName, \"overflowHidden w100 h100\")}>\n\t\t\t<Scrollable ref={ref} {...props} />\n\t\t</div>\n\t);\n});\n",".stateWrapper {\n\ttext-decoration: none;\n\tcolor: inherit;\n\tdisplay: block;\n\n\t// border: var(--border-width) solid var(--state-border-color, transparent);\n\tborder-left-style: solid;\n\tborder-left-color: var(--state-border-color, transparent);\n\tborder-left-width: 0.0625em; // 1px\n\tpadding-left: 0.25em; // 4px + 1px border\n\n\t&.status {\n\t\tborder-left-width: 0.3125em; // 5px\n\t\tpadding-left: 0;\n\n\t\t&.information {\n\t\t\tborder-left-color: var(--status-info-fill);\n\t\t}\n\n\t\t&.success {\n\t\t\tborder-left-color: var(--status-success-fill);\n\t\t}\n\n\t\t&.warning {\n\t\t\tborder-left-color: var(--status-warning-fill);\n\t\t}\n\n\t\t&.error {\n\t\t\tborder-left-color: var(--status-error-fill);\n\t\t}\n\t}\n}\n\n.state {\n\t&.information {\n\t\tcolor: var(--status-info-text);\n\n\t\tfill: var(--status-info-fill);\n\t\tstroke: var(--status-info-on-fill);\n\t}\n\n\t&.success {\n\t\tcolor: var(--status-success-text);\n\n\t\tfill: var(--status-success-fill);\n\t\tstroke: var(--status-success-on-fill);\n\t}\n\n\t&.warning {\n\t\tcolor: var(--status-warning-text);\n\n\t\tfill: var(--status-warning-fill);\n\t\tstroke: var(--status-warning-on-fill);\n\t\tstroke-width: 2px;\n\t}\n\n\t&.error {\n\t\tcolor: var(--status-error-text);\n\n\t\tfill: var(--status-error-fill);\n\t\tstroke: var(--status-error-on-fill);\n\t}\n}\n","import React from \"react\";\n\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { CircleAlertIcon, CircleCheckIcon, CircleXIcon, InfoIcon } from \"lucide-react\";\n\nimport styles from \"./State.module.scss\";\n\ninterface StateIconProps {\n\tstate: State;\n\ttext: string;\n\tclassName?: string;\n}\n\nexport const StateIcon: React.FC<StateIconProps> = ({ state = \"none\", text, className }) => {\n\tconst renderIcon = () => {\n\t\tswitch (state) {\n\t\t\tcase \"error\":\n\t\t\t\treturn <ErrorIcon />;\n\t\t\tcase \"warning\":\n\t\t\t\treturn <WarningIcon />;\n\t\t\tcase \"success\":\n\t\t\t\treturn <SuccessIcon />;\n\t\t\tcase \"information\":\n\t\t\t\treturn <InformationIcon />;\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t};\n\n\treturn (\n\t\t<div className={cn(\"flexCenter gapSm\", className)}>\n\t\t\t{renderIcon()}\n\t\t\t{text}\n\t\t</div>\n\t);\n};\n\ninterface RenderStateIconProps {\n\tstate?: State;\n}\n\nexport const RenderStateIcon: React.FC<RenderStateIconProps> = ({ state }) => {\n\tswitch (state) {\n\t\tcase \"error\":\n\t\t\treturn <ErrorIcon />;\n\t\tcase \"warning\":\n\t\t\treturn <WarningIcon />;\n\t\tcase \"success\":\n\t\t\treturn <SuccessIcon />;\n\t\tcase \"information\":\n\t\t\treturn <InformationIcon />;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\n\nexport const ErrorIcon = () => {\n\treturn <CircleXIcon className={cn(styles.state, styles.error)} />;\n};\nexport const WarningIcon = () => {\n\treturn <CircleAlertIcon className={cn(styles.state, styles.warning)} />;\n};\nexport const SuccessIcon = () => {\n\treturn <CircleCheckIcon className={cn(styles.state, styles.success)} />;\n};\nexport const InformationIcon = () => {\n\treturn <InfoIcon className={cn(styles.state, styles.information)} />;\n};\n","import React from \"react\";\n\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { PolymorphicComponent, PolymorphicComponentBaseProps } from \"../polymorphic\";\n\nimport styles from \"./State.module.scss\";\n\ntype StateWrapperOwnProps<E extends React.ElementType = React.ElementType> = PolymorphicComponentBaseProps<E> & {\n\tstate?: State;\n\tclassName?: string;\n};\n\ntype StateWrapperProps<E extends React.ElementType> = StateWrapperOwnProps<E> &\n\tOmit<React.ComponentPropsWithRef<E>, keyof StateWrapperOwnProps>;\n\nexport function StateWrapper<E extends React.ElementType>({ as, state, className, ...props }: StateWrapperProps<E>) {\n\tconst status = state?.toLowerCase() ?? \"none\";\n\tconst statusClass = styles[status as keyof typeof styles];\n\tconst isStatused = status && status !== \"none\";\n\n\tconst Component = as || \"div\";\n\n\treturn (\n\t\t<PolymorphicComponent\n\t\t\tas={Component as React.ElementType}\n\t\t\tclassName={cn(styles.stateWrapper, isStatused && styles.status, statusClass, className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { o as e } from "./flex-DYZ0IbU6.js";
2
- import { n as t } from "./button-CC0Jdx1j.js";
1
+ import { o as e } from "./flex-C7njxZ74.js";
2
+ import { n as t } from "./button-BU2kRzwu.js";
3
3
  import { r as n } from "./grid-dI94AAbi.js";
4
- import { c as r } from "./misc-DIF5h9ba.js";
4
+ import { c as r } from "./misc-BYxxlJz6.js";
5
5
  import { Children as i, createContext as a, useCallback as o, useContext as s, useEffect as c, useId as l, useRef as u, useState as d } from "react";
6
6
  import { cn as f } from "@ryuzaki13/react-foundation-lib/utils";
7
7
  import { X as p } from "lucide-react";
@@ -113,7 +113,6 @@ var M = ({ isOpen: e, title: r, size: a = "sm", height: o, onClose: s, children:
113
113
  case A.displayName:
114
114
  if (G) throw Error("Modal: duplicate <Content> found");
115
115
  G = e;
116
- break;
117
116
  }
118
117
  return y(/* @__PURE__ */ m(b, {
119
118
  onExitComplete: H,
@@ -193,4 +192,4 @@ function N({ children: e, compensateScrollbar: t = !1 }) {
193
192
  //#endregion
194
193
  export { k as a, j as i, M as n, D as o, A as r, O as s, N as t };
195
194
 
196
- //# sourceMappingURL=modal-DXHX_sA-.js.map
195
+ //# sourceMappingURL=modal-paexEF0j.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal-DXHX_sA-.js","names":[],"sources":["../../src/modal/Modal.module.scss","../../src/modal/modalMotion.ts","../../src/modal/useModalManager.ts","../../src/modal/Modal.tsx","../../src/modal/ModalManagerProvider.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.modal {\n\tdisplay: grid;\n\tgrid-auto-rows: auto 1fr;\n\n\tposition: fixed;\n\tinset: 0;\n\tmargin: auto;\n\tz-index: var(--z-modal);\n\twidth: 90%;\n\theight: fit-content;\n\tmax-height: calc(100dvh - var(--space-lg));\n\tborder: var(--border);\n\tborder-radius: var(--radius-md);\n\tbackground-color: var(--surface-1);\n\tbox-shadow: var(--shadow-lg);\n\n\t&:not(:last-child) {\n\t\tpointer-events: none;\n\t\tfilter: grayscale(0.5) opacity(0.75);\n\t\t// opacity: 0.5;\n\t}\n\n\t&.sm {\n\t\tmax-width: min(30em, 93dvw);\n\t}\n\n\t&.md {\n\t\tmax-width: min(50em, 93dvw);\n\t}\n\n\t&.lg {\n\t\tmax-width: min(70em, 93dvw);\n\t}\n\n\t&.xl {\n\t\tmax-width: min(80em, 93dvw);\n\t}\n\n\t&.xxl {\n\t\twidth: 93dvw;\n\t\theight: 90dvh;\n\t\tmax-width: none;\n\t\tmax-height: none;\n\t}\n\n\t&.inside {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmax-width: none;\n\t\tmax-height: none;\n\n\t\t.header,\n\t\t.body {\n\t\t\tborder-radius: 0;\n\t\t}\n\t}\n}\n\n.header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbackground-color: var(--surface-2);\n\tborder-top-left-radius: var(--radius-md);\n\tborder-top-right-radius: var(--radius-md);\n}\n\n.headerText {\n\tmargin: 0;\n\tpadding-inline: var(--space-md);\n\tfont-size: var(--font-size-md);\n\tfont-variation-settings: \"wght\" 600;\n}\n\n.headerButton {\n\tmargin-block: var(--space-xs);\n\tmargin-inline: var(--space-sm);\n\tflex: 0;\n}\n\n.body {\n\toverflow: hidden;\n\tborder-bottom-left-radius: var(--radius-md);\n\tborder-bottom-right-radius: var(--radius-md);\n}\n","import { type Transition, type Variants } from \"motion/react\";\n\n/**\n * Варианты задают единый спокойный переход для появления и удаления modal-панели.\n * Конфигурация приватна для primitive: потребители управляют только состоянием `isOpen`.\n */\nexport const modalMotionVariants = {\n\thidden: {\n\t\topacity: 0,\n\t\tscale: 0.96,\n\t\ty: 12\n\t},\n\tvisible: {\n\t\topacity: 1,\n\t\tscale: 1,\n\t\ty: 0\n\t}\n} satisfies Variants;\n\n/** Переход сохраняет отзывчивое открытие и дает exit-анимации завершиться до удаления portal content. */\nexport const modalMotionTransition = {\n\tduration: 0.18,\n\tease: [0.22, 1, 0.36, 1]\n} satisfies Transition;\n\n/** При системном reduced-motion остается только мгновенная смена видимости без пространственного движения. */\nexport const reducedModalMotionTransition = {\n\tduration: 0\n} satisfies Transition;\n","import { createContext, useContext } from \"react\";\n\nexport const ModalManagerContext = createContext<{\n\tmodals: string[];\n\topenModal: (id: string) => void;\n\tcloseModal: (id: string) => void;\n\tisTopModal: (id: string) => boolean;\n}>({\n\tmodals: [],\n\topenModal: () => {},\n\tcloseModal: () => {},\n\tisTopModal: () => false\n});\n\nexport const useModalManager = () => useContext(ModalManagerContext);\n","import React, { Children, useEffect, useId, useRef } from \"react\";\n\nimport { getOrCreatePortalRoot, useEscapeDismiss, useOverlayFocus } from \"@ryuzaki13/react-foundation-lib/dom\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { X } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { createPortal } from \"react-dom\";\n\nimport { Button } from \"../button\";\nimport { FlexContainer } from \"../flex\";\nimport { GridContainer } from \"../grid\";\nimport { Scrollable } from \"../misc\";\n\nimport styles from \"./Modal.module.scss\";\nimport { modalMotionTransition, modalMotionVariants, reducedModalMotionTransition } from \"./modalMotion\";\nimport { ModalSize } from \"./types\";\nimport { useModalManager } from \"./useModalManager\";\n\n// Подкомпоненты\nexport interface ModalCompositionProps {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n}\n\nexport const ModalToolbar: React.FC<ModalCompositionProps> = ({ children, className }) => {\n\treturn <div className={cn(\"surface2 paddingMd borderBottom\", className)}>{children}</div>;\n};\nModalToolbar.displayName = \"Modal.Toolbar\";\n\nexport const ModalContent: React.FC<ModalCompositionProps & { scrollable?: boolean }> = ({ children, className, scrollable }) => {\n\treturn (\n\t\t<div className={cn(\"paddingMd h100 overflowHidden\", className)}>\n\t\t\t{scrollable ? <Scrollable className=\"h100\">{children}</Scrollable> : children}\n\t\t</div>\n\t);\n};\nModalContent.displayName = \"Modal.Content\";\n\nexport const ModalFooter: React.FC<ModalCompositionProps> = ({ children, className }) => {\n\treturn (\n\t\t<div className={cn(\"surface2 borderTop paddingMd\", className)}>\n\t\t\t<FlexContainer gap=\"sm\" align=\"center\" justify=\"end\">\n\t\t\t\t{children}\n\t\t\t</FlexContainer>\n\t\t</div>\n\t);\n};\nModalFooter.displayName = \"Modal.Footer\";\n\ntype ToolbarElement = React.ReactElement<ModalCompositionProps, typeof ModalToolbar>;\ntype ContentElement = React.ReactElement<ModalCompositionProps, typeof ModalContent>;\ntype FooterElement = React.ReactElement<ModalCompositionProps, typeof ModalFooter>;\n\ntype ModalChildren =\n\t[ToolbarElement, ContentElement, FooterElement] | [ToolbarElement, ContentElement] | [ContentElement, FooterElement] | ContentElement;\n\nexport interface ModalProps {\n\t/** Открыто ли модальное окно */\n\tisOpen?: boolean;\n\t/** Заголовок */\n\ttitle?: string;\n\t/** Размер модального окна */\n\tsize?: keyof typeof ModalSize;\n\theight?: string;\n\t/** Обработчик закрытия */\n\tonClose: () => void;\n\tchildren: ModalChildren;\n}\n\nexport const Modal: React.FC<ModalProps> = ({ isOpen, title, size = \"sm\", height, onClose, children }) => {\n\tconst modalId = useId();\n\tconst titleId = useId();\n\n\tconst { modals, openModal, closeModal, isTopModal } = useModalManager();\n\tconst shouldReduceMotion = useReducedMotion();\n\tconst restoreFocusTargetRef = useRef<HTMLElement | null>(null);\n\tconst restoreFocusAnimationFrameRef = useRef(0);\n\n\t/**\n\t * Если provider менеджера не подключен, считаем одиночную модалку активной,\n\t * иначе логика Escape/focus trap никогда не включится.\n\t */\n\tconst isActive = isOpen && (modals.length === 0 || isTopModal(modalId));\n\n\tuseEffect(() => {\n\t\tif (isOpen) {\n\t\t\trestoreFocusTargetRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\t}\n\t}, [isOpen]);\n\n\tconst modalRef = useOverlayFocus<HTMLDivElement>({ active: isOpen || false, trapFocus: true, restoreFocus: false });\n\n\tuseEscapeDismiss({\n\t\tactive: isActive || false,\n\t\tonDismiss: onClose,\n\t\tcontainerRef: modalRef\n\t});\n\n\tuseEffect(() => {\n\t\tif (isOpen) {\n\t\t\topenModal(modalId);\n\t\t}\n\t}, [isOpen, modalId, openModal]);\n\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\twindow.cancelAnimationFrame(restoreFocusAnimationFrameRef.current);\n\t\t\tcloseModal(modalId);\n\t\t};\n\t}, [closeModal, modalId]);\n\n\tfunction handleExitComplete() {\n\t\tcloseModal(modalId);\n\t\tconst restoreFocusTarget = restoreFocusTargetRef.current;\n\n\t\t/**\n\t\t * Менеджер снимает inert в passive effect после обновления стека.\n\t\t * Следующий animation frame гарантирует, что trigger снова доступен для фокуса.\n\t\t */\n\t\trestoreFocusAnimationFrameRef.current = window.requestAnimationFrame(() => {\n\t\t\tif (restoreFocusTarget?.isConnected) {\n\t\t\t\trestoreFocusTarget.focus();\n\t\t\t}\n\t\t\trestoreFocusTargetRef.current = null;\n\t\t});\n\t}\n\n\tconst modalRoot = getOrCreatePortalRoot(\"modal-root\");\n\n\tif (!modalRoot) {\n\t\treturn null;\n\t}\n\n\tlet toolbar: React.ReactNode = null;\n\tlet content: React.ReactNode = null;\n\tlet footer: React.ReactNode = null;\n\n\tconst childArray = Children.toArray(children) as (ToolbarElement | ContentElement | FooterElement)[];\n\n\tfor (const child of childArray) {\n\t\tconst typeName = child.type.displayName;\n\n\t\tswitch (typeName) {\n\t\t\tcase ModalToolbar.displayName:\n\t\t\t\tif (toolbar) throw new Error(\"Modal: duplicate <Toolbar> found\");\n\t\t\t\ttoolbar = child; //.props.children;\n\t\t\t\tbreak;\n\t\t\tcase ModalFooter.displayName:\n\t\t\t\tif (footer) throw new Error(\"Modal: duplicate <Footer> found\");\n\t\t\t\tfooter = child; //props.children;\n\t\t\t\tbreak;\n\t\t\tcase ModalContent.displayName:\n\t\t\t\tif (content) throw new Error(\"Modal: duplicate <Content> found\");\n\t\t\t\tcontent = child; //.props.children;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn createPortal(\n\t\t<AnimatePresence onExitComplete={handleExitComplete}>\n\t\t\t{isOpen ? (\n\t\t\t\t<motion.div\n\t\t\t\t\tref={modalRef}\n\t\t\t\t\tclassName={cn(styles.modal, styles[size])}\n\t\t\t\t\tstyle={{ height }}\n\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\taria-labelledby={titleId}\n\t\t\t\t\taria-describedby={`${titleId}-content`}\n\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\texit=\"hidden\"\n\t\t\t\t\tvariants={modalMotionVariants}\n\t\t\t\t\ttransition={shouldReduceMotion ? reducedModalMotionTransition : modalMotionTransition}>\n\t\t\t\t\t<div className={cn(styles.header, toolbar ? \"\" : \"borderBottom\")}>\n\t\t\t\t\t\t<h3 className={styles.headerText} id={titleId}>\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ticon={<X />}\n\t\t\t\t\t\t\tclassName={styles.headerButton}\n\t\t\t\t\t\t\tvariant={\"ghost\"}\n\t\t\t\t\t\t\taria-label={\"Закрыть модальное окно\"}\n\t\t\t\t\t\t\tonClick={onClose}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<GridContainer\n\t\t\t\t\t\tid={`${titleId}-content`}\n\t\t\t\t\t\ttemplateRows={`${toolbar ? \"auto\" : \"\"} 1fr ${footer ? \"auto\" : \"\"}`.trim()}\n\t\t\t\t\t\t// gap=\"md\"\n\t\t\t\t\t\tclassName={styles.body}>\n\t\t\t\t\t\t{toolbar}\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t{footer}\n\t\t\t\t\t</GridContainer>\n\t\t\t\t</motion.div>\n\t\t\t) : null}\n\t\t</AnimatePresence>,\n\t\tmodalRoot\n\t);\n};\n","// ModalManagerContext.tsx\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { ModalManagerContext } from \"./useModalManager\";\n\nexport interface ModalManagerProviderProps {\n\tchildren: React.ReactNode;\n\t/** Компенсирует исчезновение скроллбара правым padding у body. */\n\tcompensateScrollbar?: boolean;\n}\n\n/**\n * Провайдер для централизованного управления стеком модальных окон. Дает вложенным компонентам доступ к открытию и закрытию модалок через контекст.\n */\nexport function ModalManagerProvider({ children, compensateScrollbar = false }: ModalManagerProviderProps) {\n\tconst [modals, setModals] = useState<string[]>([]);\n\tconst prevModalsLength = useRef(0);\n\tconst scrollbarWidth = useRef(0);\n\tconst bodyPaddingRight = useRef(\"\");\n\tconst isScrollbarCompensated = useRef(false);\n\n\tconst openModal = useCallback((id: string) => {\n\t\tsetModals((prev) => [...prev, id]);\n\t}, []);\n\n\tconst closeModal = useCallback((id: string) => {\n\t\tsetModals((prev) => prev.filter((mid) => mid !== id));\n\t}, []);\n\n\tconst isTopModal = useCallback(\n\t\t(id: string) => {\n\t\t\treturn modals[modals.length - 1] === id;\n\t\t},\n\t\t[modals]\n\t);\n\n\tuseEffect(() => {\n\t\tconst wasEmpty = prevModalsLength.current === 0;\n\n\t\tif (wasEmpty && modals.length > 0) {\n\t\t\t// первая модалка открыта — ставим стили\n\t\t\tconst scrollY = window.scrollY;\n\t\t\tconst appRoot = document.querySelector(\"#app-root\");\n\t\t\tscrollbarWidth.current = Math.max(0, window.innerWidth - document.documentElement.clientWidth);\n\t\t\tbodyPaddingRight.current = document.body.style.paddingRight;\n\n\t\t\tdocument.body.style.position = \"fixed\";\n\t\t\tdocument.body.style.top = `-${scrollY}px`;\n\t\t\tdocument.body.style.width = \"100%\";\n\n\t\t\tif (compensateScrollbar) {\n\t\t\t\tdocument.body.style.paddingRight = `${scrollbarWidth.current}px`;\n\t\t\t\tisScrollbarCompensated.current = true;\n\t\t\t}\n\n\t\t\tappRoot?.setAttribute(\"inert\", \"true\");\n\n\t\t\tprevModalsLength.current = modals.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!wasEmpty && modals.length > 0 && compensateScrollbar !== isScrollbarCompensated.current) {\n\t\t\tdocument.body.style.paddingRight = compensateScrollbar ? `${scrollbarWidth.current}px` : bodyPaddingRight.current;\n\t\t\tisScrollbarCompensated.current = compensateScrollbar;\n\t\t}\n\n\t\tif (!wasEmpty && modals.length === 0) {\n\t\t\t// последняя модалка закрыта — снимаем стили\n\t\t\tconst appRoot = document.querySelector(\"#app-root\");\n\t\t\tconst scrollY = parseInt(document.body.style.top || \"0\") * -1;\n\n\t\t\tdocument.body.style.position = \"\";\n\t\t\tdocument.body.style.top = \"\";\n\t\t\tdocument.body.style.width = \"\";\n\n\t\t\tif (isScrollbarCompensated.current) {\n\t\t\t\tdocument.body.style.paddingRight = bodyPaddingRight.current;\n\t\t\t\tisScrollbarCompensated.current = false;\n\t\t\t}\n\n\t\t\tappRoot?.removeAttribute(\"inert\");\n\n\t\t\twindow.scrollTo({ top: scrollY, left: 0, behavior: \"instant\" });\n\t\t}\n\n\t\tprevModalsLength.current = modals.length;\n\t}, [compensateScrollbar, modals.length]);\n\n\treturn <ModalManagerContext.Provider value={{ modals, openModal, closeModal, isTopModal }}>{children}</ModalManagerContext.Provider>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;GCMa,IAAsB;CAClC,QAAQ;EACP,SAAS;EACT,OAAO;EACP,GAAG;CACJ;CACA,SAAS;EACR,SAAS;EACT,OAAO;EACP,GAAG;CACJ;AACD,GAGa,IAAwB;CACpC,UAAU;CACV,MAAM;EAAC;EAAM;EAAG;EAAM;CAAC;AACxB,GAGa,IAA+B,EAC3C,UAAU,EACX,GC1Ba,IAAsB,EAKhC;CACF,QAAQ,CAAC;CACT,iBAAiB,CAAC;CAClB,kBAAkB,CAAC;CACnB,kBAAkB;AACnB,CAAC,GAEY,UAAwB,EAAW,CAAmB,GCUtD,KAAiD,EAAE,aAAU,mBAClE,kBAAC,OAAD;CAAK,WAAW,EAAG,mCAAmC,CAAS;CAAI;AAAc,CAAA;AAEzF,EAAa,cAAc;AAE3B,IAAa,KAA4E,EAAE,aAAU,cAAW,oBAE9G,kBAAC,OAAD;CAAK,WAAW,EAAG,iCAAiC,CAAS;WAC3D,IAAa,kBAAC,GAAD;EAAY,WAAU;EAAQ;CAAqB,CAAA,IAAI;AACjE,CAAA;AAGP,EAAa,cAAc;AAE3B,IAAa,KAAgD,EAAE,aAAU,mBAEvE,kBAAC,OAAD;CAAK,WAAW,EAAG,gCAAgC,CAAS;WAC3D,kBAAC,GAAD;EAAe,KAAI;EAAK,OAAM;EAAS,SAAQ;EAC7C;CACa,CAAA;AACX,CAAA;AAGP,EAAY,cAAc;AAsB1B,IAAa,KAA+B,EAAE,WAAQ,UAAO,UAAO,MAAM,WAAQ,YAAS,kBAAe;CACzG,IAAM,IAAU,EAAM,GAChB,IAAU,EAAM,GAEhB,EAAE,WAAQ,cAAW,eAAY,kBAAe,EAAgB,GAChE,IAAqB,EAAiB,GACtC,IAAwB,EAA2B,IAAI,GACvD,IAAgC,EAAO,CAAC,GAMxC,IAAW,MAAW,EAAO,WAAW,KAAK,EAAW,CAAO;CAErE,QAAgB;EACf,AAAI,MACH,EAAsB,UAAU,SAAS,yBAAyB,cAAc,SAAS,gBAAgB;CAE3G,GAAG,CAAC,CAAM,CAAC;CAEX,IAAM,IAAW,EAAgC;EAAE,QAAQ,KAAU;EAAO,WAAW;EAAM,cAAc;CAAM,CAAC;CAclH,AAZA,EAAiB;EAChB,QAAQ,KAAY;EACpB,WAAW;EACX,cAAc;CACf,CAAC,GAED,QAAgB;EACf,AAAI,KACH,EAAU,CAAO;CAEnB,GAAG;EAAC;EAAQ;EAAS;CAAS,CAAC,GAE/B,cACc;EAEZ,AADA,OAAO,qBAAqB,EAA8B,OAAO,GACjE,EAAW,CAAO;CACnB,GACE,CAAC,GAAY,CAAO,CAAC;CAExB,SAAS,IAAqB;EAC7B,EAAW,CAAO;EAClB,IAAM,IAAqB,EAAsB;EAMjD,EAA8B,UAAU,OAAO,4BAA4B;GAI1E,AAHI,GAAoB,eACvB,EAAmB,MAAM,GAE1B,EAAsB,UAAU;EACjC,CAAC;CACF;CAEA,IAAM,IAAY,EAAsB,YAAY;CAEpD,IAAI,CAAC,GACJ,OAAO;CAGR,IAAI,IAA2B,MAC3B,IAA2B,MAC3B,IAA0B,MAExB,IAAa,EAAS,QAAQ,CAAQ;CAE5C,KAAK,IAAM,KAAS,GAGnB,QAFiB,EAAM,KAAK,aAE5B;EACC,KAAK,EAAa;GACjB,IAAI,GAAS,MAAU,MAAM,kCAAkC;GAC/D,IAAU;GACV;EACD,KAAK,EAAY;GAChB,IAAI,GAAQ,MAAU,MAAM,iCAAiC;GAC7D,IAAS;GACT;EACD,KAAK,EAAa;GACjB,IAAI,GAAS,MAAU,MAAM,kCAAkC;GAC/D,IAAU;GACV;CACF;CAGD,OAAO,EACN,kBAAC,GAAD;EAAiB,gBAAgB;YAC/B,IACA,kBAAC,EAAO,KAAR;GACC,KAAK;GACL,WAAW,EAAG,EAAO,OAAO,EAAO,EAAK;GACxC,OAAO,EAAE,UAAO;GAChB,MAAK;GACL,cAAW;GACX,mBAAiB;GACjB,oBAAkB,GAAG,EAAQ;GAC7B,SAAQ;GACR,SAAQ;GACR,MAAK;GACL,UAAU;GACV,YAAY,IAAqB,IAA+B;aAZjE,CAaC,kBAAC,OAAD;IAAK,WAAW,EAAG,EAAO,QAAQ,IAAU,KAAK,cAAc;cAA/D,CACC,kBAAC,MAAD;KAAI,WAAW,EAAO;KAAY,IAAI;eACpC;IACE,CAAA,GACJ,kBAAC,GAAD;KACC,MAAM,kBAAC,GAAD,CAAI,CAAA;KACV,WAAW,EAAO;KAClB,SAAS;KACT,cAAY;KACZ,SAAS;IACT,CAAA,CACG;OAEL,kBAAC,GAAD;IACC,IAAI,GAAG,EAAQ;IACf,cAAc,GAAG,IAAU,SAAS,GAAG,OAAO,IAAS,SAAS,KAAK,KAAK;IAE1E,WAAW,EAAO;cAJnB;KAKE;KACA;KACA;IACa;KACJ;OACT;CACY,CAAA,GACjB,CACD;AACD;;;AC3LA,SAAgB,EAAqB,EAAE,aAAU,yBAAsB,MAAoC;CAC1G,IAAM,CAAC,GAAQ,KAAa,EAAmB,CAAC,CAAC,GAC3C,IAAmB,EAAO,CAAC,GAC3B,IAAiB,EAAO,CAAC,GACzB,IAAmB,EAAO,EAAE,GAC5B,IAAyB,EAAO,EAAK,GAErC,IAAY,GAAa,MAAe;EAC7C,GAAW,MAAS,CAAC,GAAG,GAAM,CAAE,CAAC;CAClC,GAAG,CAAC,CAAC,GAEC,IAAa,GAAa,MAAe;EAC9C,GAAW,MAAS,EAAK,QAAQ,MAAQ,MAAQ,CAAE,CAAC;CACrD,GAAG,CAAC,CAAC,GAEC,IAAa,GACjB,MACO,EAAO,EAAO,SAAS,OAAO,GAEtC,CAAC,CAAM,CACR;CAsDA,OApDA,QAAgB;EACf,IAAM,IAAW,EAAiB,YAAY;EAE9C,IAAI,KAAY,EAAO,SAAS,GAAG;GAElC,IAAM,IAAU,OAAO,SACjB,IAAU,SAAS,cAAc,WAAW;GAelD,AAdA,EAAe,UAAU,KAAK,IAAI,GAAG,OAAO,aAAa,SAAS,gBAAgB,WAAW,GAC7F,EAAiB,UAAU,SAAS,KAAK,MAAM,cAE/C,SAAS,KAAK,MAAM,WAAW,SAC/B,SAAS,KAAK,MAAM,MAAM,IAAI,EAAQ,KACtC,SAAS,KAAK,MAAM,QAAQ,QAExB,MACH,SAAS,KAAK,MAAM,eAAe,GAAG,EAAe,QAAQ,KAC7D,EAAuB,UAAU,KAGlC,GAAS,aAAa,SAAS,MAAM,GAErC,EAAiB,UAAU,EAAO;GAClC;EACD;EAOA,IALI,CAAC,KAAY,EAAO,SAAS,KAAK,MAAwB,EAAuB,YACpF,SAAS,KAAK,MAAM,eAAe,IAAsB,GAAG,EAAe,QAAQ,MAAM,EAAiB,SAC1G,EAAuB,UAAU,IAG9B,CAAC,KAAY,EAAO,WAAW,GAAG;GAErC,IAAM,IAAU,SAAS,cAAc,WAAW,GAC5C,IAAU,SAAS,SAAS,KAAK,MAAM,OAAO,GAAG,IAAI;GAa3D,AAXA,SAAS,KAAK,MAAM,WAAW,IAC/B,SAAS,KAAK,MAAM,MAAM,IAC1B,SAAS,KAAK,MAAM,QAAQ,IAE5B,AAEC,EAAuB,aADvB,SAAS,KAAK,MAAM,eAAe,EAAiB,SACnB,KAGlC,GAAS,gBAAgB,OAAO,GAEhC,OAAO,SAAS;IAAE,KAAK;IAAS,MAAM;IAAG,UAAU;GAAU,CAAC;EAC/D;EAEA,EAAiB,UAAU,EAAO;CACnC,GAAG,CAAC,GAAqB,EAAO,MAAM,CAAC,GAEhC,kBAAC,EAAoB,UAArB;EAA8B,OAAO;GAAE;GAAQ;GAAW;GAAY;EAAW;EAAI;CAAuC,CAAA;AACpI"}
1
+ {"version":3,"file":"modal-paexEF0j.js","names":[],"sources":["../../src/modal/Modal.module.scss","../../src/modal/modalMotion.ts","../../src/modal/useModalManager.ts","../../src/modal/Modal.tsx","../../src/modal/ModalManagerProvider.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.modal {\n\tdisplay: grid;\n\tgrid-auto-rows: auto 1fr;\n\n\tposition: fixed;\n\tinset: 0;\n\tmargin: auto;\n\tz-index: var(--z-modal);\n\twidth: 90%;\n\theight: fit-content;\n\tmax-height: calc(100dvh - var(--space-lg));\n\tborder: var(--border);\n\tborder-radius: var(--radius-md);\n\tbackground-color: var(--surface-1);\n\tbox-shadow: var(--shadow-lg);\n\n\t&:not(:last-child) {\n\t\tpointer-events: none;\n\t\tfilter: grayscale(0.5) opacity(0.75);\n\t\t// opacity: 0.5;\n\t}\n\n\t&.sm {\n\t\tmax-width: min(30em, 93dvw);\n\t}\n\n\t&.md {\n\t\tmax-width: min(50em, 93dvw);\n\t}\n\n\t&.lg {\n\t\tmax-width: min(70em, 93dvw);\n\t}\n\n\t&.xl {\n\t\tmax-width: min(80em, 93dvw);\n\t}\n\n\t&.xxl {\n\t\twidth: 93dvw;\n\t\theight: 90dvh;\n\t\tmax-width: none;\n\t\tmax-height: none;\n\t}\n\n\t&.inside {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmax-width: none;\n\t\tmax-height: none;\n\n\t\t.header,\n\t\t.body {\n\t\t\tborder-radius: 0;\n\t\t}\n\t}\n}\n\n.header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbackground-color: var(--surface-2);\n\tborder-top-left-radius: var(--radius-md);\n\tborder-top-right-radius: var(--radius-md);\n}\n\n.headerText {\n\tmargin: 0;\n\tpadding-inline: var(--space-md);\n\tfont-size: var(--font-size-md);\n\tfont-variation-settings: \"wght\" 600;\n}\n\n.headerButton {\n\tmargin-block: var(--space-xs);\n\tmargin-inline: var(--space-sm);\n\tflex: 0;\n}\n\n.body {\n\toverflow: hidden;\n\tborder-bottom-left-radius: var(--radius-md);\n\tborder-bottom-right-radius: var(--radius-md);\n}\n","import { type Transition, type Variants } from \"motion/react\";\n\n/**\n * Варианты задают единый спокойный переход для появления и удаления modal-панели.\n * Конфигурация приватна для primitive: потребители управляют только состоянием `isOpen`.\n */\nexport const modalMotionVariants = {\n\thidden: {\n\t\topacity: 0,\n\t\tscale: 0.96,\n\t\ty: 12\n\t},\n\tvisible: {\n\t\topacity: 1,\n\t\tscale: 1,\n\t\ty: 0\n\t}\n} satisfies Variants;\n\n/** Переход сохраняет отзывчивое открытие и дает exit-анимации завершиться до удаления portal content. */\nexport const modalMotionTransition = {\n\tduration: 0.18,\n\tease: [0.22, 1, 0.36, 1]\n} satisfies Transition;\n\n/** При системном reduced-motion остается только мгновенная смена видимости без пространственного движения. */\nexport const reducedModalMotionTransition = {\n\tduration: 0\n} satisfies Transition;\n","import { createContext, useContext } from \"react\";\n\nexport const ModalManagerContext = createContext<{\n\tmodals: string[];\n\topenModal: (id: string) => void;\n\tcloseModal: (id: string) => void;\n\tisTopModal: (id: string) => boolean;\n}>({\n\tmodals: [],\n\topenModal: () => {},\n\tcloseModal: () => {},\n\tisTopModal: () => false\n});\n\nexport const useModalManager = () => useContext(ModalManagerContext);\n","import React, { Children, useEffect, useId, useRef } from \"react\";\n\nimport { getOrCreatePortalRoot, useEscapeDismiss, useOverlayFocus } from \"@ryuzaki13/react-foundation-lib/dom\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { X } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { createPortal } from \"react-dom\";\n\nimport { Button } from \"../button\";\nimport { FlexContainer } from \"../flex\";\nimport { GridContainer } from \"../grid\";\nimport { Scrollable } from \"../misc\";\n\nimport styles from \"./Modal.module.scss\";\nimport { modalMotionTransition, modalMotionVariants, reducedModalMotionTransition } from \"./modalMotion\";\nimport { ModalSize } from \"./types\";\nimport { useModalManager } from \"./useModalManager\";\n\n// Подкомпоненты\nexport interface ModalCompositionProps {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n}\n\nexport const ModalToolbar: React.FC<ModalCompositionProps> = ({ children, className }) => {\n\treturn <div className={cn(\"surface2 paddingMd borderBottom\", className)}>{children}</div>;\n};\nModalToolbar.displayName = \"Modal.Toolbar\";\n\nexport const ModalContent: React.FC<ModalCompositionProps & { scrollable?: boolean }> = ({ children, className, scrollable }) => {\n\treturn (\n\t\t<div className={cn(\"paddingMd h100 overflowHidden\", className)}>\n\t\t\t{scrollable ? <Scrollable className=\"h100\">{children}</Scrollable> : children}\n\t\t</div>\n\t);\n};\nModalContent.displayName = \"Modal.Content\";\n\nexport const ModalFooter: React.FC<ModalCompositionProps> = ({ children, className }) => {\n\treturn (\n\t\t<div className={cn(\"surface2 borderTop paddingMd\", className)}>\n\t\t\t<FlexContainer gap=\"sm\" align=\"center\" justify=\"end\">\n\t\t\t\t{children}\n\t\t\t</FlexContainer>\n\t\t</div>\n\t);\n};\nModalFooter.displayName = \"Modal.Footer\";\n\ntype ToolbarElement = React.ReactElement<ModalCompositionProps, typeof ModalToolbar>;\ntype ContentElement = React.ReactElement<ModalCompositionProps, typeof ModalContent>;\ntype FooterElement = React.ReactElement<ModalCompositionProps, typeof ModalFooter>;\n\ntype ModalChildren =\n\t[ToolbarElement, ContentElement, FooterElement] | [ToolbarElement, ContentElement] | [ContentElement, FooterElement] | ContentElement;\n\nexport interface ModalProps {\n\t/** Открыто ли модальное окно */\n\tisOpen?: boolean;\n\t/** Заголовок */\n\ttitle?: string;\n\t/** Размер модального окна */\n\tsize?: keyof typeof ModalSize;\n\theight?: string;\n\t/** Обработчик закрытия */\n\tonClose: () => void;\n\tchildren: ModalChildren;\n}\n\nexport const Modal: React.FC<ModalProps> = ({ isOpen, title, size = \"sm\", height, onClose, children }) => {\n\tconst modalId = useId();\n\tconst titleId = useId();\n\n\tconst { modals, openModal, closeModal, isTopModal } = useModalManager();\n\tconst shouldReduceMotion = useReducedMotion();\n\tconst restoreFocusTargetRef = useRef<HTMLElement | null>(null);\n\tconst restoreFocusAnimationFrameRef = useRef(0);\n\n\t/**\n\t * Если provider менеджера не подключен, считаем одиночную модалку активной,\n\t * иначе логика Escape/focus trap никогда не включится.\n\t */\n\tconst isActive = isOpen && (modals.length === 0 || isTopModal(modalId));\n\n\tuseEffect(() => {\n\t\tif (isOpen) {\n\t\t\trestoreFocusTargetRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\t}\n\t}, [isOpen]);\n\n\tconst modalRef = useOverlayFocus<HTMLDivElement>({ active: isOpen || false, trapFocus: true, restoreFocus: false });\n\n\tuseEscapeDismiss({\n\t\tactive: isActive || false,\n\t\tonDismiss: onClose,\n\t\tcontainerRef: modalRef\n\t});\n\n\tuseEffect(() => {\n\t\tif (isOpen) {\n\t\t\topenModal(modalId);\n\t\t}\n\t}, [isOpen, modalId, openModal]);\n\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\twindow.cancelAnimationFrame(restoreFocusAnimationFrameRef.current);\n\t\t\tcloseModal(modalId);\n\t\t};\n\t}, [closeModal, modalId]);\n\n\tfunction handleExitComplete() {\n\t\tcloseModal(modalId);\n\t\tconst restoreFocusTarget = restoreFocusTargetRef.current;\n\n\t\t/**\n\t\t * Менеджер снимает inert в passive effect после обновления стека.\n\t\t * Следующий animation frame гарантирует, что trigger снова доступен для фокуса.\n\t\t */\n\t\trestoreFocusAnimationFrameRef.current = window.requestAnimationFrame(() => {\n\t\t\tif (restoreFocusTarget?.isConnected) {\n\t\t\t\trestoreFocusTarget.focus();\n\t\t\t}\n\t\t\trestoreFocusTargetRef.current = null;\n\t\t});\n\t}\n\n\tconst modalRoot = getOrCreatePortalRoot(\"modal-root\");\n\n\tif (!modalRoot) {\n\t\treturn null;\n\t}\n\n\tlet toolbar: React.ReactNode = null;\n\tlet content: React.ReactNode = null;\n\tlet footer: React.ReactNode = null;\n\n\tconst childArray = Children.toArray(children) as (ToolbarElement | ContentElement | FooterElement)[];\n\n\tfor (const child of childArray) {\n\t\tconst typeName = child.type.displayName;\n\n\t\tswitch (typeName) {\n\t\t\tcase ModalToolbar.displayName:\n\t\t\t\tif (toolbar) throw new Error(\"Modal: duplicate <Toolbar> found\");\n\t\t\t\ttoolbar = child; //.props.children;\n\t\t\t\tbreak;\n\t\t\tcase ModalFooter.displayName:\n\t\t\t\tif (footer) throw new Error(\"Modal: duplicate <Footer> found\");\n\t\t\t\tfooter = child; //props.children;\n\t\t\t\tbreak;\n\t\t\tcase ModalContent.displayName:\n\t\t\t\tif (content) throw new Error(\"Modal: duplicate <Content> found\");\n\t\t\t\tcontent = child; //.props.children;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn createPortal(\n\t\t<AnimatePresence onExitComplete={handleExitComplete}>\n\t\t\t{isOpen ? (\n\t\t\t\t<motion.div\n\t\t\t\t\tref={modalRef}\n\t\t\t\t\tclassName={cn(styles.modal, styles[size])}\n\t\t\t\t\tstyle={{ height }}\n\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\taria-labelledby={titleId}\n\t\t\t\t\taria-describedby={`${titleId}-content`}\n\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\texit=\"hidden\"\n\t\t\t\t\tvariants={modalMotionVariants}\n\t\t\t\t\ttransition={shouldReduceMotion ? reducedModalMotionTransition : modalMotionTransition}>\n\t\t\t\t\t<div className={cn(styles.header, toolbar ? \"\" : \"borderBottom\")}>\n\t\t\t\t\t\t<h3 className={styles.headerText} id={titleId}>\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ticon={<X />}\n\t\t\t\t\t\t\tclassName={styles.headerButton}\n\t\t\t\t\t\t\tvariant={\"ghost\"}\n\t\t\t\t\t\t\taria-label={\"Закрыть модальное окно\"}\n\t\t\t\t\t\t\tonClick={onClose}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<GridContainer\n\t\t\t\t\t\tid={`${titleId}-content`}\n\t\t\t\t\t\ttemplateRows={`${toolbar ? \"auto\" : \"\"} 1fr ${footer ? \"auto\" : \"\"}`.trim()}\n\t\t\t\t\t\t// gap=\"md\"\n\t\t\t\t\t\tclassName={styles.body}>\n\t\t\t\t\t\t{toolbar}\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t{footer}\n\t\t\t\t\t</GridContainer>\n\t\t\t\t</motion.div>\n\t\t\t) : null}\n\t\t</AnimatePresence>,\n\t\tmodalRoot\n\t);\n};\n","// ModalManagerContext.tsx\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { ModalManagerContext } from \"./useModalManager\";\n\nexport interface ModalManagerProviderProps {\n\tchildren: React.ReactNode;\n\t/** Компенсирует исчезновение скроллбара правым padding у body. */\n\tcompensateScrollbar?: boolean;\n}\n\n/**\n * Провайдер для централизованного управления стеком модальных окон. Дает вложенным компонентам доступ к открытию и закрытию модалок через контекст.\n */\nexport function ModalManagerProvider({ children, compensateScrollbar = false }: ModalManagerProviderProps) {\n\tconst [modals, setModals] = useState<string[]>([]);\n\tconst prevModalsLength = useRef(0);\n\tconst scrollbarWidth = useRef(0);\n\tconst bodyPaddingRight = useRef(\"\");\n\tconst isScrollbarCompensated = useRef(false);\n\n\tconst openModal = useCallback((id: string) => {\n\t\tsetModals((prev) => [...prev, id]);\n\t}, []);\n\n\tconst closeModal = useCallback((id: string) => {\n\t\tsetModals((prev) => prev.filter((mid) => mid !== id));\n\t}, []);\n\n\tconst isTopModal = useCallback(\n\t\t(id: string) => {\n\t\t\treturn modals[modals.length - 1] === id;\n\t\t},\n\t\t[modals]\n\t);\n\n\tuseEffect(() => {\n\t\tconst wasEmpty = prevModalsLength.current === 0;\n\n\t\tif (wasEmpty && modals.length > 0) {\n\t\t\t// первая модалка открыта — ставим стили\n\t\t\tconst scrollY = window.scrollY;\n\t\t\tconst appRoot = document.querySelector(\"#app-root\");\n\t\t\tscrollbarWidth.current = Math.max(0, window.innerWidth - document.documentElement.clientWidth);\n\t\t\tbodyPaddingRight.current = document.body.style.paddingRight;\n\n\t\t\tdocument.body.style.position = \"fixed\";\n\t\t\tdocument.body.style.top = `-${scrollY}px`;\n\t\t\tdocument.body.style.width = \"100%\";\n\n\t\t\tif (compensateScrollbar) {\n\t\t\t\tdocument.body.style.paddingRight = `${scrollbarWidth.current}px`;\n\t\t\t\tisScrollbarCompensated.current = true;\n\t\t\t}\n\n\t\t\tappRoot?.setAttribute(\"inert\", \"true\");\n\n\t\t\tprevModalsLength.current = modals.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!wasEmpty && modals.length > 0 && compensateScrollbar !== isScrollbarCompensated.current) {\n\t\t\tdocument.body.style.paddingRight = compensateScrollbar ? `${scrollbarWidth.current}px` : bodyPaddingRight.current;\n\t\t\tisScrollbarCompensated.current = compensateScrollbar;\n\t\t}\n\n\t\tif (!wasEmpty && modals.length === 0) {\n\t\t\t// последняя модалка закрыта — снимаем стили\n\t\t\tconst appRoot = document.querySelector(\"#app-root\");\n\t\t\tconst scrollY = parseInt(document.body.style.top || \"0\") * -1;\n\n\t\t\tdocument.body.style.position = \"\";\n\t\t\tdocument.body.style.top = \"\";\n\t\t\tdocument.body.style.width = \"\";\n\n\t\t\tif (isScrollbarCompensated.current) {\n\t\t\t\tdocument.body.style.paddingRight = bodyPaddingRight.current;\n\t\t\t\tisScrollbarCompensated.current = false;\n\t\t\t}\n\n\t\t\tappRoot?.removeAttribute(\"inert\");\n\n\t\t\twindow.scrollTo({ top: scrollY, left: 0, behavior: \"instant\" });\n\t\t}\n\n\t\tprevModalsLength.current = modals.length;\n\t}, [compensateScrollbar, modals.length]);\n\n\treturn <ModalManagerContext.Provider value={{ modals, openModal, closeModal, isTopModal }}>{children}</ModalManagerContext.Provider>;\n}\n"],"mappings":"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"}