@techzyapp/ui-library 1.0.48 → 1.0.50

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 (480) hide show
  1. package/dist/{Accordion-DOrTQJB9.js → Accordion-C6vW_OMd.js} +2 -2
  2. package/dist/{Accordion-DOrTQJB9.js.map → Accordion-C6vW_OMd.js.map} +1 -1
  3. package/dist/{Accordion-CFyeLfPT.cjs → Accordion-Icvl9S8c.cjs} +2 -2
  4. package/dist/{Accordion-CFyeLfPT.cjs.map → Accordion-Icvl9S8c.cjs.map} +1 -1
  5. package/dist/{AdminRoot-DX6glneh.js → AdminRoot-C5l8PIyi.js} +9 -9
  6. package/dist/{AdminRoot-DX6glneh.js.map → AdminRoot-C5l8PIyi.js.map} +1 -1
  7. package/dist/{AdminRoot-DAz9u2Yc.cjs → AdminRoot-MEfy9xtz.cjs} +2 -2
  8. package/dist/{AdminRoot-DAz9u2Yc.cjs.map → AdminRoot-MEfy9xtz.cjs.map} +1 -1
  9. package/dist/{Alert-QvfNBhlU.cjs → Alert--ZnlCjaL.cjs} +2 -2
  10. package/dist/{Alert-QvfNBhlU.cjs.map → Alert--ZnlCjaL.cjs.map} +1 -1
  11. package/dist/{Alert-Bo_XgY-A.js → Alert-BVs-GcZQ.js} +4 -4
  12. package/dist/{Alert-Bo_XgY-A.js.map → Alert-BVs-GcZQ.js.map} +1 -1
  13. package/dist/AuthGuard-Cm-tqCto.cjs +2 -0
  14. package/dist/AuthGuard-Cm-tqCto.cjs.map +1 -0
  15. package/dist/AuthGuard-DJ_mMwfg.js +114 -0
  16. package/dist/AuthGuard-DJ_mMwfg.js.map +1 -0
  17. package/dist/{AuthLayout-BI1wLuDl.js → AuthLayout-BDRJFSpi.js} +2 -2
  18. package/dist/{AuthLayout-BI1wLuDl.js.map → AuthLayout-BDRJFSpi.js.map} +1 -1
  19. package/dist/{AuthLayout-Bzlsvicf.cjs → AuthLayout-D7mSMdM4.cjs} +2 -2
  20. package/dist/{AuthLayout-Bzlsvicf.cjs.map → AuthLayout-D7mSMdM4.cjs.map} +1 -1
  21. package/dist/{Avatar-BBqX1732.cjs → Avatar-BwGJl-ru.cjs} +2 -2
  22. package/dist/{Avatar-BBqX1732.cjs.map → Avatar-BwGJl-ru.cjs.map} +1 -1
  23. package/dist/{Avatar-CaYyv5wk.js → Avatar-C4qgzth2.js} +2 -2
  24. package/dist/{Avatar-CaYyv5wk.js.map → Avatar-C4qgzth2.js.map} +1 -1
  25. package/dist/{AvatarGroup-DrkzAt1-.cjs → AvatarGroup-B8u8ONs5.cjs} +2 -2
  26. package/dist/{AvatarGroup-DrkzAt1-.cjs.map → AvatarGroup-B8u8ONs5.cjs.map} +1 -1
  27. package/dist/{AvatarGroup-6fhm-van.js → AvatarGroup-BqxTFzRc.js} +2 -2
  28. package/dist/{AvatarGroup-6fhm-van.js.map → AvatarGroup-BqxTFzRc.js.map} +1 -1
  29. package/dist/{Breadcrumbs-CqGS32x5.cjs → Breadcrumbs-D4wv2-T7.cjs} +2 -2
  30. package/dist/{Breadcrumbs-CqGS32x5.cjs.map → Breadcrumbs-D4wv2-T7.cjs.map} +1 -1
  31. package/dist/{Breadcrumbs-BEv57tuJ.js → Breadcrumbs-HGk4DKrc.js} +4 -4
  32. package/dist/{Breadcrumbs-BEv57tuJ.js.map → Breadcrumbs-HGk4DKrc.js.map} +1 -1
  33. package/dist/{Button-DZWYeAno.js → Button-7mgXcRdw.js} +2 -2
  34. package/dist/{Button-DZWYeAno.js.map → Button-7mgXcRdw.js.map} +1 -1
  35. package/dist/{Button-BtiFpRie.cjs → Button-DAvQCGIw.cjs} +2 -2
  36. package/dist/{Button-BtiFpRie.cjs.map → Button-DAvQCGIw.cjs.map} +1 -1
  37. package/dist/{Calendar-7W9xNVBZ.js → Calendar-B1ZJHqjB.js} +4 -4
  38. package/dist/{Calendar-7W9xNVBZ.js.map → Calendar-B1ZJHqjB.js.map} +1 -1
  39. package/dist/{Calendar-Bgh_3Vk2.cjs → Calendar-BPYjqBy9.cjs} +2 -2
  40. package/dist/{Calendar-Bgh_3Vk2.cjs.map → Calendar-BPYjqBy9.cjs.map} +1 -1
  41. package/dist/{Card-KfmWG9Uz.cjs → Card-B-Qso__1.cjs} +2 -2
  42. package/dist/{Card-KfmWG9Uz.cjs.map → Card-B-Qso__1.cjs.map} +1 -1
  43. package/dist/{Card-ckOd617g.js → Card-vFsIhkyR.js} +4 -4
  44. package/dist/{Card-ckOd617g.js.map → Card-vFsIhkyR.js.map} +1 -1
  45. package/dist/{Chip-Crzm7Eux.js → Chip-CU0J7HJa.js} +3 -3
  46. package/dist/{Chip-Crzm7Eux.js.map → Chip-CU0J7HJa.js.map} +1 -1
  47. package/dist/{Chip-BDUsue_R.cjs → Chip-CovsonP1.cjs} +2 -2
  48. package/dist/{Chip-BDUsue_R.cjs.map → Chip-CovsonP1.cjs.map} +1 -1
  49. package/dist/{ChoiceCardGroup-D37XREKV.js → ChoiceCardGroup-BBqUbFLS.js} +2 -2
  50. package/dist/{ChoiceCardGroup-D37XREKV.js.map → ChoiceCardGroup-BBqUbFLS.js.map} +1 -1
  51. package/dist/{ChoiceCardGroup-Cj_YFj6C.cjs → ChoiceCardGroup-bnKFPDYz.cjs} +2 -2
  52. package/dist/{ChoiceCardGroup-Cj_YFj6C.cjs.map → ChoiceCardGroup-bnKFPDYz.cjs.map} +1 -1
  53. package/dist/{CodeBlock-rnGAu2DQ.cjs → CodeBlock-B404V_cc.cjs} +2 -2
  54. package/dist/{CodeBlock-rnGAu2DQ.cjs.map → CodeBlock-B404V_cc.cjs.map} +1 -1
  55. package/dist/{CodeBlock-CX8_dMPD.js → CodeBlock-DvJ45qEp.js} +4 -4
  56. package/dist/{CodeBlock-CX8_dMPD.js.map → CodeBlock-DvJ45qEp.js.map} +1 -1
  57. package/dist/{ColorPicker-CwLivdAt.js → ColorPicker-C4slmEZC.js} +3 -3
  58. package/dist/{ColorPicker-CwLivdAt.js.map → ColorPicker-C4slmEZC.js.map} +1 -1
  59. package/dist/{ColorPicker-BaAdcqR9.cjs → ColorPicker-_RBW51XB.cjs} +2 -2
  60. package/dist/{ColorPicker-BaAdcqR9.cjs.map → ColorPicker-_RBW51XB.cjs.map} +1 -1
  61. package/dist/{ColorPickerPanel-IOhJJF1R.cjs → ColorPickerPanel-CNspBZre.cjs} +2 -2
  62. package/dist/{ColorPickerPanel-IOhJJF1R.cjs.map → ColorPickerPanel-CNspBZre.cjs.map} +1 -1
  63. package/dist/{ColorPickerPanel-CkrSIf35.js → ColorPickerPanel-CQNfIbgc.js} +3 -3
  64. package/dist/{ColorPickerPanel-CkrSIf35.js.map → ColorPickerPanel-CQNfIbgc.js.map} +1 -1
  65. package/dist/{ColorRamp-DbFOsspz.js → ColorRamp-DQZZiE5I.js} +2 -2
  66. package/dist/{ColorRamp-DbFOsspz.js.map → ColorRamp-DQZZiE5I.js.map} +1 -1
  67. package/dist/{ColorRamp-BCy8a7ks.cjs → ColorRamp-DuO7gkru.cjs} +2 -2
  68. package/dist/{ColorRamp-BCy8a7ks.cjs.map → ColorRamp-DuO7gkru.cjs.map} +1 -1
  69. package/dist/{ConfigProvider-CYSpuSMJ.cjs → ConfigProvider-BFhkb0BV.cjs} +2 -2
  70. package/dist/{ConfigProvider-CYSpuSMJ.cjs.map → ConfigProvider-BFhkb0BV.cjs.map} +1 -1
  71. package/dist/{ConfigProvider-DtyUlWk6.js → ConfigProvider-bXX8dnhY.js} +2 -2
  72. package/dist/{ConfigProvider-DtyUlWk6.js.map → ConfigProvider-bXX8dnhY.js.map} +1 -1
  73. package/dist/{CopyButton-DUG5s3TM.cjs → CopyButton-B2V6guZ0.cjs} +2 -2
  74. package/dist/{CopyButton-DUG5s3TM.cjs.map → CopyButton-B2V6guZ0.cjs.map} +1 -1
  75. package/dist/{CopyButton-LURMuaYw.js → CopyButton-DfYAslz-.js} +4 -4
  76. package/dist/{CopyButton-LURMuaYw.js.map → CopyButton-DfYAslz-.js.map} +1 -1
  77. package/dist/{DashedButton-BX8hfY1x.cjs → DashedButton-CZ2hjLxT.cjs} +2 -2
  78. package/dist/{DashedButton-BX8hfY1x.cjs.map → DashedButton-CZ2hjLxT.cjs.map} +1 -1
  79. package/dist/{DashedButton-wcmXTYBw.js → DashedButton-meJSIY61.js} +2 -2
  80. package/dist/{DashedButton-wcmXTYBw.js.map → DashedButton-meJSIY61.js.map} +1 -1
  81. package/dist/{DatePicker-CSIBYSZt.js → DatePicker-CNUDjOxA.js} +5 -5
  82. package/dist/{DatePicker-CSIBYSZt.js.map → DatePicker-CNUDjOxA.js.map} +1 -1
  83. package/dist/{DatePicker-Bw9gLB8o.cjs → DatePicker-DrIHa1j1.cjs} +2 -2
  84. package/dist/{DatePicker-Bw9gLB8o.cjs.map → DatePicker-DrIHa1j1.cjs.map} +1 -1
  85. package/dist/{DateTimePicker-kikKdt0F.cjs → DateTimePicker-BzwxaOPb.cjs} +2 -2
  86. package/dist/{DateTimePicker-kikKdt0F.cjs.map → DateTimePicker-BzwxaOPb.cjs.map} +1 -1
  87. package/dist/{DateTimePicker-C9F2yJMf.js → DateTimePicker-CvWNDbib.js} +8 -8
  88. package/dist/{DateTimePicker-C9F2yJMf.js.map → DateTimePicker-CvWNDbib.js.map} +1 -1
  89. package/dist/{DescriptionList-DnGkHdzT.cjs → DescriptionList-Bed1MHU8.cjs} +2 -2
  90. package/dist/{DescriptionList-DnGkHdzT.cjs.map → DescriptionList-Bed1MHU8.cjs.map} +1 -1
  91. package/dist/{DescriptionList-kfNXbf_D.js → DescriptionList-BgMNjHJQ.js} +5 -5
  92. package/dist/{DescriptionList-kfNXbf_D.js.map → DescriptionList-BgMNjHJQ.js.map} +1 -1
  93. package/dist/{Dropdown-C_y9_dVn.cjs → Dropdown-DNL7RWdL.cjs} +2 -2
  94. package/dist/{Dropdown-C_y9_dVn.cjs.map → Dropdown-DNL7RWdL.cjs.map} +1 -1
  95. package/dist/{Dropdown-D-D_Z1Jo.js → Dropdown-iWbHokT7.js} +2 -2
  96. package/dist/{Dropdown-D-D_Z1Jo.js.map → Dropdown-iWbHokT7.js.map} +1 -1
  97. package/dist/{EmptyState-BM5LrRLq.cjs → EmptyState-BzwrOICc.cjs} +2 -2
  98. package/dist/{EmptyState-BM5LrRLq.cjs.map → EmptyState-BzwrOICc.cjs.map} +1 -1
  99. package/dist/{EmptyState-DrSj2XV_.js → EmptyState-CmcjJl_K.js} +3 -3
  100. package/dist/{EmptyState-DrSj2XV_.js.map → EmptyState-CmcjJl_K.js.map} +1 -1
  101. package/dist/{ErrorBoundary-yz669VEu.cjs → ErrorBoundary-BcZgeSsu.cjs} +2 -2
  102. package/dist/{ErrorBoundary-yz669VEu.cjs.map → ErrorBoundary-BcZgeSsu.cjs.map} +1 -1
  103. package/dist/{ErrorBoundary-DsP4hO_V.js → ErrorBoundary-TfeJetWc.js} +3 -3
  104. package/dist/{ErrorBoundary-DsP4hO_V.js.map → ErrorBoundary-TfeJetWc.js.map} +1 -1
  105. package/dist/{ErrorState-BThPIYaM.cjs → ErrorState-CzWz5UcX.cjs} +2 -2
  106. package/dist/{ErrorState-BThPIYaM.cjs.map → ErrorState-CzWz5UcX.cjs.map} +1 -1
  107. package/dist/{ErrorState-DEngucdq.js → ErrorState-EjIhdq7S.js} +8 -8
  108. package/dist/{ErrorState-DEngucdq.js.map → ErrorState-EjIhdq7S.js.map} +1 -1
  109. package/dist/{FileCard-CmCESTQd.js → FileCard-CmMxVyk3.js} +5 -5
  110. package/dist/{FileCard-CmCESTQd.js.map → FileCard-CmMxVyk3.js.map} +1 -1
  111. package/dist/{FileCard-wxDT2rj9.cjs → FileCard-Cxr1_eF2.cjs} +2 -2
  112. package/dist/{FileCard-wxDT2rj9.cjs.map → FileCard-Cxr1_eF2.cjs.map} +1 -1
  113. package/dist/{FileUploader-Dp1r4Sxc.js → FileUploader-2cXBI4Nh.js} +7 -7
  114. package/dist/{FileUploader-Dp1r4Sxc.js.map → FileUploader-2cXBI4Nh.js.map} +1 -1
  115. package/dist/{FileUploader-DBNRp5eT.cjs → FileUploader-BkM1t2aE.cjs} +2 -2
  116. package/dist/{FileUploader-DBNRp5eT.cjs.map → FileUploader-BkM1t2aE.cjs.map} +1 -1
  117. package/dist/{Flag-B6OhgwZr.cjs → Flag-CWp81_zX.cjs} +2 -2
  118. package/dist/{Flag-B6OhgwZr.cjs.map → Flag-CWp81_zX.cjs.map} +1 -1
  119. package/dist/{Flag-Q3vI7cgt.js → Flag-IQolG3j6.js} +2 -2
  120. package/dist/{Flag-Q3vI7cgt.js.map → Flag-IQolG3j6.js.map} +1 -1
  121. package/dist/{FullscreenToggle-WGsbE3Op.js → FullscreenToggle-B1DH_-k3.js} +4 -4
  122. package/dist/{FullscreenToggle-WGsbE3Op.js.map → FullscreenToggle-B1DH_-k3.js.map} +1 -1
  123. package/dist/{FullscreenToggle-DVdQriWB.cjs → FullscreenToggle-DXVAeN3M.cjs} +2 -2
  124. package/dist/{FullscreenToggle-DVdQriWB.cjs.map → FullscreenToggle-DXVAeN3M.cjs.map} +1 -1
  125. package/dist/Icon-BoQmbW7j.cjs +2 -0
  126. package/dist/Icon-BoQmbW7j.cjs.map +1 -0
  127. package/dist/{Icon-B7DJn8Tw.js → Icon-DMMO32p6.js} +72 -71
  128. package/dist/Icon-DMMO32p6.js.map +1 -0
  129. package/dist/{IconButton-DSPdv-oI.cjs → IconButton-ChhZqleN.cjs} +2 -2
  130. package/dist/{IconButton-DSPdv-oI.cjs.map → IconButton-ChhZqleN.cjs.map} +1 -1
  131. package/dist/{IconButton-iWbUJAz7.js → IconButton-s5hohjxu.js} +2 -2
  132. package/dist/{IconButton-iWbUJAz7.js.map → IconButton-s5hohjxu.js.map} +1 -1
  133. package/dist/{ImageEditor-C40dp2-V.cjs → ImageEditor-C8tFTX4e.cjs} +2 -2
  134. package/dist/{ImageEditor-C40dp2-V.cjs.map → ImageEditor-C8tFTX4e.cjs.map} +1 -1
  135. package/dist/{ImageEditor-BDNys8pq.js → ImageEditor-DWbWjGQ8.js} +8 -8
  136. package/dist/{ImageEditor-BDNys8pq.js.map → ImageEditor-DWbWjGQ8.js.map} +1 -1
  137. package/dist/{List-DS91CZUt.js → List-DQlEG_S5.js} +2 -2
  138. package/dist/{List-DS91CZUt.js.map → List-DQlEG_S5.js.map} +1 -1
  139. package/dist/{List-CLUXeaXS.cjs → List-Dfa7mlSZ.cjs} +2 -2
  140. package/dist/{List-CLUXeaXS.cjs.map → List-Dfa7mlSZ.cjs.map} +1 -1
  141. package/dist/{ListItem-Ezmdk7q-.js → ListItem-CLmg9xKQ.js} +2 -2
  142. package/dist/{ListItem-Ezmdk7q-.js.map → ListItem-CLmg9xKQ.js.map} +1 -1
  143. package/dist/{ListItem-CguNjf-u.cjs → ListItem-CWM2fUS2.cjs} +2 -2
  144. package/dist/{ListItem-CguNjf-u.cjs.map → ListItem-CWM2fUS2.cjs.map} +1 -1
  145. package/dist/{Loader-RyFTP2X5.cjs → Loader-BCrMy9NU.cjs} +2 -2
  146. package/dist/{Loader-RyFTP2X5.cjs.map → Loader-BCrMy9NU.cjs.map} +1 -1
  147. package/dist/{Loader-DD1vfqmN.js → Loader-CShIWNfG.js} +2 -2
  148. package/dist/{Loader-DD1vfqmN.js.map → Loader-CShIWNfG.js.map} +1 -1
  149. package/dist/{LocationPicker-B594f0bz.cjs → LocationPicker-8Tt0zJU4.cjs} +2 -2
  150. package/dist/{LocationPicker-B594f0bz.cjs.map → LocationPicker-8Tt0zJU4.cjs.map} +1 -1
  151. package/dist/{LocationPicker-DpmYaYyd.js → LocationPicker-DsV_s2Ur.js} +8 -8
  152. package/dist/{LocationPicker-DpmYaYyd.js.map → LocationPicker-DsV_s2Ur.js.map} +1 -1
  153. package/dist/{Modal-DVGTD2Ck.js → Modal-BO7fHn0r.js} +4 -4
  154. package/dist/{Modal-DVGTD2Ck.js.map → Modal-BO7fHn0r.js.map} +1 -1
  155. package/dist/{Modal-7cCok6fV.cjs → Modal-yj92WLay.cjs} +2 -2
  156. package/dist/{Modal-7cCok6fV.cjs.map → Modal-yj92WLay.cjs.map} +1 -1
  157. package/dist/{MultiSelect-DTKNjUDH.cjs → MultiSelect-B6JZb_5N.cjs} +2 -2
  158. package/dist/{MultiSelect-DTKNjUDH.cjs.map → MultiSelect-B6JZb_5N.cjs.map} +1 -1
  159. package/dist/{MultiSelect-D-X833xt.js → MultiSelect-D-QWlfwD.js} +5 -5
  160. package/dist/{MultiSelect-D-X833xt.js.map → MultiSelect-D-QWlfwD.js.map} +1 -1
  161. package/dist/{NumberField-Xz4yQMlm.cjs → NumberField-CS5VMnk4.cjs} +2 -2
  162. package/dist/{NumberField-Xz4yQMlm.cjs.map → NumberField-CS5VMnk4.cjs.map} +1 -1
  163. package/dist/{NumberField-OPOl0Yph.js → NumberField-D_UxKjVN.js} +4 -4
  164. package/dist/{NumberField-OPOl0Yph.js.map → NumberField-D_UxKjVN.js.map} +1 -1
  165. package/dist/{OtpField-kd0YghZq.cjs → OtpField-BuS_8j9L.cjs} +2 -2
  166. package/dist/{OtpField-kd0YghZq.cjs.map → OtpField-BuS_8j9L.cjs.map} +1 -1
  167. package/dist/{OtpField-CLrDMNtS.js → OtpField-CpjDid5_.js} +2 -2
  168. package/dist/{OtpField-CLrDMNtS.js.map → OtpField-CpjDid5_.js.map} +1 -1
  169. package/dist/{PageError-v6MAH_OL.cjs → PageError-CTEOASeb.cjs} +2 -2
  170. package/dist/{PageError-v6MAH_OL.cjs.map → PageError-CTEOASeb.cjs.map} +1 -1
  171. package/dist/{PageError-BIiZDzey.js → PageError-DjyJrGmR.js} +5 -5
  172. package/dist/{PageError-BIiZDzey.js.map → PageError-DjyJrGmR.js.map} +1 -1
  173. package/dist/{PageLayout-DH3jochw.cjs → PageLayout-BYKRmCAL.cjs} +2 -2
  174. package/dist/{PageLayout-DH3jochw.cjs.map → PageLayout-BYKRmCAL.cjs.map} +1 -1
  175. package/dist/{PageLayout-BjaPfXvb.js → PageLayout-Cz1OhQZ7.js} +5 -5
  176. package/dist/{PageLayout-BjaPfXvb.js.map → PageLayout-Cz1OhQZ7.js.map} +1 -1
  177. package/dist/{PageNotFound-C1oSsMG-.js → PageNotFound-CwBtrllo.js} +5 -5
  178. package/dist/{PageNotFound-C1oSsMG-.js.map → PageNotFound-CwBtrllo.js.map} +1 -1
  179. package/dist/{PageNotFound-Cse4bROv.cjs → PageNotFound-u9Q4KG6B.cjs} +2 -2
  180. package/dist/{PageNotFound-Cse4bROv.cjs.map → PageNotFound-u9Q4KG6B.cjs.map} +1 -1
  181. package/dist/{Pagination-BNJdqcu4.js → Pagination-CLjNwqie.js} +3 -3
  182. package/dist/{Pagination-BNJdqcu4.js.map → Pagination-CLjNwqie.js.map} +1 -1
  183. package/dist/{Pagination-DkmfEmgK.cjs → Pagination-HtS5gPnd.cjs} +2 -2
  184. package/dist/{Pagination-DkmfEmgK.cjs.map → Pagination-HtS5gPnd.cjs.map} +1 -1
  185. package/dist/{PaletteField-DqZl1mK0.cjs → PaletteField-BSgx5pxh.cjs} +2 -2
  186. package/dist/{PaletteField-DqZl1mK0.cjs.map → PaletteField-BSgx5pxh.cjs.map} +1 -1
  187. package/dist/{PaletteField-Cdky6Zka.js → PaletteField-Bk7cnSla.js} +3 -3
  188. package/dist/{PaletteField-Cdky6Zka.js.map → PaletteField-Bk7cnSla.js.map} +1 -1
  189. package/dist/{PhoneField-jq-3_i_b.cjs → PhoneField-CzFv2Vci.cjs} +2 -2
  190. package/dist/{PhoneField-jq-3_i_b.cjs.map → PhoneField-CzFv2Vci.cjs.map} +1 -1
  191. package/dist/{PhoneField-DmFaJJEa.js → PhoneField-DhoumZNG.js} +5 -5
  192. package/dist/{PhoneField-DmFaJJEa.js.map → PhoneField-DhoumZNG.js.map} +1 -1
  193. package/dist/{Popconfirm-KOE9gGi6.cjs → Popconfirm-Cb9LlmZb.cjs} +2 -2
  194. package/dist/{Popconfirm-KOE9gGi6.cjs.map → Popconfirm-Cb9LlmZb.cjs.map} +1 -1
  195. package/dist/{Popconfirm-D-8ZG2WR.js → Popconfirm-D7J5JbF-.js} +4 -4
  196. package/dist/{Popconfirm-D-8ZG2WR.js.map → Popconfirm-D7J5JbF-.js.map} +1 -1
  197. package/dist/{Progress-CdX666FP.js → Progress-Bt2LDqbD.js} +2 -2
  198. package/dist/{Progress-CdX666FP.js.map → Progress-Bt2LDqbD.js.map} +1 -1
  199. package/dist/{Progress-7EyhPtnu.cjs → Progress-dAtQ2BN-.cjs} +2 -2
  200. package/dist/{Progress-7EyhPtnu.cjs.map → Progress-dAtQ2BN-.cjs.map} +1 -1
  201. package/dist/{QrCode-ClIJjjvF.cjs → QrCode-FHUAxI8u.cjs} +2 -2
  202. package/dist/{QrCode-ClIJjjvF.cjs.map → QrCode-FHUAxI8u.cjs.map} +1 -1
  203. package/dist/{QrCode-D7ocSDi7.js → QrCode-jaDZxZkv.js} +2 -2
  204. package/dist/{QrCode-D7ocSDi7.js.map → QrCode-jaDZxZkv.js.map} +1 -1
  205. package/dist/{RemoveDialog-DTzRPLaT.js → RemoveDialog-DdO5E3Wl.js} +6 -6
  206. package/dist/{RemoveDialog-DTzRPLaT.js.map → RemoveDialog-DdO5E3Wl.js.map} +1 -1
  207. package/dist/{RemoveDialog-UsSX5z8Y.cjs → RemoveDialog-eGNxdyoO.cjs} +2 -2
  208. package/dist/{RemoveDialog-UsSX5z8Y.cjs.map → RemoveDialog-eGNxdyoO.cjs.map} +1 -1
  209. package/dist/{RichTextEditor-Bh0Q3dIW.cjs → RichTextEditor-CoYuQurR.cjs} +2 -2
  210. package/dist/{RichTextEditor-Bh0Q3dIW.cjs.map → RichTextEditor-CoYuQurR.cjs.map} +1 -1
  211. package/dist/{RichTextEditor-BMctlkVC.js → RichTextEditor-DHRiJchI.js} +10 -10
  212. package/dist/{RichTextEditor-BMctlkVC.js.map → RichTextEditor-DHRiJchI.js.map} +1 -1
  213. package/dist/{RootLayout-BztZetpk.cjs → RootLayout-CEplIlVR.cjs} +2 -2
  214. package/dist/{RootLayout-BztZetpk.cjs.map → RootLayout-CEplIlVR.cjs.map} +1 -1
  215. package/dist/{RootLayout-CTkv4iQJ.js → RootLayout-pd66MZtI.js} +21 -21
  216. package/dist/{RootLayout-CTkv4iQJ.js.map → RootLayout-pd66MZtI.js.map} +1 -1
  217. package/dist/{Select-CmonDIIU.js → Select-C2iiQLMh.js} +4 -4
  218. package/dist/{Select-CmonDIIU.js.map → Select-C2iiQLMh.js.map} +1 -1
  219. package/dist/{Select-BzVyK6Ne.cjs → Select-CvW_T9R-.cjs} +2 -2
  220. package/dist/{Select-BzVyK6Ne.cjs.map → Select-CvW_T9R-.cjs.map} +1 -1
  221. package/dist/Sidebar-CqGCazeA.cjs +2 -0
  222. package/dist/Sidebar-CqGCazeA.cjs.map +1 -0
  223. package/dist/Sidebar-DuUhzQBi.js +543 -0
  224. package/dist/Sidebar-DuUhzQBi.js.map +1 -0
  225. package/dist/{Slider-Oe9VSAdy.cjs → Slider-DlPMPdHA.cjs} +2 -2
  226. package/dist/{Slider-Oe9VSAdy.cjs.map → Slider-DlPMPdHA.cjs.map} +1 -1
  227. package/dist/{Slider-C7Wb3q_F.js → Slider-UY29adRu.js} +2 -2
  228. package/dist/{Slider-C7Wb3q_F.js.map → Slider-UY29adRu.js.map} +1 -1
  229. package/dist/{SpeedDial-DpIXoYHB.cjs → SpeedDial-Cms5pJ9t.cjs} +2 -2
  230. package/dist/{SpeedDial-DpIXoYHB.cjs.map → SpeedDial-Cms5pJ9t.cjs.map} +1 -1
  231. package/dist/{SpeedDial-CCGQlwn2.js → SpeedDial-DOWefQgo.js} +3 -3
  232. package/dist/{SpeedDial-CCGQlwn2.js.map → SpeedDial-DOWefQgo.js.map} +1 -1
  233. package/dist/{Stepper-PBDU60G_.cjs → Stepper-4wCyTnwi.cjs} +2 -2
  234. package/dist/{Stepper-PBDU60G_.cjs.map → Stepper-4wCyTnwi.cjs.map} +1 -1
  235. package/dist/{Stepper-D_WKS1RG.js → Stepper-yQEJkbUJ.js} +3 -3
  236. package/dist/{Stepper-D_WKS1RG.js.map → Stepper-yQEJkbUJ.js.map} +1 -1
  237. package/dist/{SwatchPicker-DS4WY2eM.js → SwatchPicker-BI0XHphv.js} +2 -2
  238. package/dist/{SwatchPicker-DS4WY2eM.js.map → SwatchPicker-BI0XHphv.js.map} +1 -1
  239. package/dist/{SwatchPicker-DCjE0T80.cjs → SwatchPicker-QYtqEUxX.cjs} +2 -2
  240. package/dist/{SwatchPicker-DCjE0T80.cjs.map → SwatchPicker-QYtqEUxX.cjs.map} +1 -1
  241. package/dist/{Table-DZQVa_PE.js → Table-CNrt1EWm.js} +19 -19
  242. package/dist/{Table-DZQVa_PE.js.map → Table-CNrt1EWm.js.map} +1 -1
  243. package/dist/{Table-CZ4n4-TN.cjs → Table-D4pqLNtE.cjs} +2 -2
  244. package/dist/{Table-CZ4n4-TN.cjs.map → Table-D4pqLNtE.cjs.map} +1 -1
  245. package/dist/{Tabs-Byhqm-TE.cjs → Tabs-D6qrgZTM.cjs} +2 -2
  246. package/dist/{Tabs-Byhqm-TE.cjs.map → Tabs-D6qrgZTM.cjs.map} +1 -1
  247. package/dist/{Tabs-B063mP-v.js → Tabs-lezN63jW.js} +3 -3
  248. package/dist/{Tabs-B063mP-v.js.map → Tabs-lezN63jW.js.map} +1 -1
  249. package/dist/{TagsField-g_LtwYgz.cjs → TagsField-BIJEDyfz.cjs} +2 -2
  250. package/dist/{TagsField-g_LtwYgz.cjs.map → TagsField-BIJEDyfz.cjs.map} +1 -1
  251. package/dist/{TagsField-hQFYyNcM.js → TagsField-D_a2I8eU.js} +5 -5
  252. package/dist/{TagsField-hQFYyNcM.js.map → TagsField-D_a2I8eU.js.map} +1 -1
  253. package/dist/{TextField-Dfpk0jOg.js → TextField-BsC2zoHI.js} +4 -4
  254. package/dist/{TextField-Dfpk0jOg.js.map → TextField-BsC2zoHI.js.map} +1 -1
  255. package/dist/{TextField-D4s2hGSd.cjs → TextField-CXDBlP-8.cjs} +2 -2
  256. package/dist/{TextField-D4s2hGSd.cjs.map → TextField-CXDBlP-8.cjs.map} +1 -1
  257. package/dist/{ThemeToggle-BQQ3eswr.js → ThemeToggle-Dh6XxqM7.js} +4 -4
  258. package/dist/{ThemeToggle-BQQ3eswr.js.map → ThemeToggle-Dh6XxqM7.js.map} +1 -1
  259. package/dist/{ThemeToggle-BTTI7Jz0.cjs → ThemeToggle-zbKf4ph5.cjs} +2 -2
  260. package/dist/{ThemeToggle-BTTI7Jz0.cjs.map → ThemeToggle-zbKf4ph5.cjs.map} +1 -1
  261. package/dist/{TimeColumns-BpjhrNCq.js → TimeColumns-CR__2LXh.js} +2 -2
  262. package/dist/{TimeColumns-BpjhrNCq.js.map → TimeColumns-CR__2LXh.js.map} +1 -1
  263. package/dist/{TimeColumns-DZYGWWG_.cjs → TimeColumns-CjBeUPtV.cjs} +2 -2
  264. package/dist/{TimeColumns-DZYGWWG_.cjs.map → TimeColumns-CjBeUPtV.cjs.map} +1 -1
  265. package/dist/{TimePicker-mzoMIlpq.js → TimePicker-BakQ-wPd.js} +6 -6
  266. package/dist/{TimePicker-mzoMIlpq.js.map → TimePicker-BakQ-wPd.js.map} +1 -1
  267. package/dist/{TimePicker-DChtZgBs.cjs → TimePicker-DtqmD2bH.cjs} +2 -2
  268. package/dist/{TimePicker-DChtZgBs.cjs.map → TimePicker-DtqmD2bH.cjs.map} +1 -1
  269. package/dist/{Timeline-DOojNvLG.cjs → Timeline-CFKbPpAV.cjs} +2 -2
  270. package/dist/{Timeline-DOojNvLG.cjs.map → Timeline-CFKbPpAV.cjs.map} +1 -1
  271. package/dist/{Timeline-Dg03dwTN.js → Timeline-zCHcq7Ra.js} +2 -2
  272. package/dist/{Timeline-Dg03dwTN.js.map → Timeline-zCHcq7Ra.js.map} +1 -1
  273. package/dist/{Toaster-lonArt-H.cjs → Toaster-BpXPWJ_n.cjs} +2 -2
  274. package/dist/{Toaster-lonArt-H.cjs.map → Toaster-BpXPWJ_n.cjs.map} +1 -1
  275. package/dist/{Toaster-79DvOW80.js → Toaster-C5jWNL-o.js} +3 -3
  276. package/dist/{Toaster-79DvOW80.js.map → Toaster-C5jWNL-o.js.map} +1 -1
  277. package/dist/{ToggleButtonGroup-CGNRLxjg.cjs → ToggleButtonGroup-CbKtjm8O.cjs} +2 -2
  278. package/dist/{ToggleButtonGroup-CGNRLxjg.cjs.map → ToggleButtonGroup-CbKtjm8O.cjs.map} +1 -1
  279. package/dist/{ToggleButtonGroup-K6ZcrTZT.js → ToggleButtonGroup-D3Jltv0z.js} +2 -2
  280. package/dist/{ToggleButtonGroup-K6ZcrTZT.js.map → ToggleButtonGroup-D3Jltv0z.js.map} +1 -1
  281. package/dist/{TranslatedFields-CHHtXO_n.js → TranslatedFields-C8oxlGIQ.js} +5 -5
  282. package/dist/{TranslatedFields-CHHtXO_n.js.map → TranslatedFields-C8oxlGIQ.js.map} +1 -1
  283. package/dist/{TranslatedFields-BYpMrYaw.cjs → TranslatedFields-Che_ZPHk.cjs} +2 -2
  284. package/dist/{TranslatedFields-BYpMrYaw.cjs.map → TranslatedFields-Che_ZPHk.cjs.map} +1 -1
  285. package/dist/{UserCard-SlkCgZS9.cjs → UserCard-DlrdIJHW.cjs} +2 -2
  286. package/dist/{UserCard-SlkCgZS9.cjs.map → UserCard-DlrdIJHW.cjs.map} +1 -1
  287. package/dist/{UserCard-BJFNP_nl.js → UserCard-Dr1A_bdA.js} +5 -5
  288. package/dist/{UserCard-BJFNP_nl.js.map → UserCard-Dr1A_bdA.js.map} +1 -1
  289. package/dist/auth/AuthGuard.d.cts +3 -1
  290. package/dist/auth/AuthGuard.d.ts +3 -1
  291. package/dist/auth/authLayoutRoute.d.cts +4 -3
  292. package/dist/auth/authLayoutRoute.d.ts +4 -3
  293. package/dist/auth/authRedirect.d.cts +13 -5
  294. package/dist/auth/authRedirect.d.ts +13 -5
  295. package/dist/{authLayoutRoute-AiQqIH85.cjs → authLayoutRoute-CPLqQVvx.cjs} +2 -2
  296. package/dist/authLayoutRoute-CPLqQVvx.cjs.map +1 -0
  297. package/dist/{authLayoutRoute-Nf2PDNDN.js → authLayoutRoute-nSZq8JYA.js} +2 -2
  298. package/dist/authLayoutRoute-nSZq8JYA.js.map +1 -0
  299. package/dist/chunks/icons/{62-Bfupp-0A.js → 62-9nuZO-ct.js} +9 -10
  300. package/dist/chunks/icons/{62-CZZzM1ev.cjs → 62-DQQ1U3IB.cjs} +1 -1
  301. package/dist/components/Accordion/index.cjs +1 -1
  302. package/dist/components/Accordion/index.js +1 -1
  303. package/dist/components/Alert/index.cjs +1 -1
  304. package/dist/components/Alert/index.js +1 -1
  305. package/dist/components/AuthLayout/index.cjs +1 -1
  306. package/dist/components/AuthLayout/index.js +1 -1
  307. package/dist/components/Avatar/index.cjs +1 -1
  308. package/dist/components/Avatar/index.js +2 -2
  309. package/dist/components/Breadcrumbs/index.cjs +1 -1
  310. package/dist/components/Breadcrumbs/index.js +1 -1
  311. package/dist/components/Button/index.cjs +1 -1
  312. package/dist/components/Button/index.js +1 -1
  313. package/dist/components/Card/index.cjs +1 -1
  314. package/dist/components/Card/index.js +1 -1
  315. package/dist/components/Chip/index.cjs +1 -1
  316. package/dist/components/Chip/index.js +1 -1
  317. package/dist/components/ChoiceCard/index.cjs +1 -1
  318. package/dist/components/ChoiceCard/index.js +1 -1
  319. package/dist/components/CodeBlock/index.cjs +1 -1
  320. package/dist/components/CodeBlock/index.js +1 -1
  321. package/dist/components/ColorPicker/index.cjs +1 -1
  322. package/dist/components/ColorPicker/index.js +1 -1
  323. package/dist/components/ColorRamp/index.cjs +1 -1
  324. package/dist/components/ColorRamp/index.js +1 -1
  325. package/dist/components/CopyButton/index.cjs +1 -1
  326. package/dist/components/CopyButton/index.js +1 -1
  327. package/dist/components/DashedButton/index.cjs +1 -1
  328. package/dist/components/DashedButton/index.js +1 -1
  329. package/dist/components/DatePicker/index.cjs +1 -1
  330. package/dist/components/DatePicker/index.js +1 -1
  331. package/dist/components/DateTimePicker/index.cjs +1 -1
  332. package/dist/components/DateTimePicker/index.js +1 -1
  333. package/dist/components/DescriptionList/index.cjs +1 -1
  334. package/dist/components/DescriptionList/index.js +1 -1
  335. package/dist/components/Dropdown/index.cjs +1 -1
  336. package/dist/components/Dropdown/index.js +1 -1
  337. package/dist/components/EmptyState/index.cjs +1 -1
  338. package/dist/components/EmptyState/index.js +1 -1
  339. package/dist/components/ErrorState/index.cjs +1 -1
  340. package/dist/components/ErrorState/index.js +2 -2
  341. package/dist/components/FileCard/index.cjs +1 -1
  342. package/dist/components/FileCard/index.js +1 -1
  343. package/dist/components/FileUploader/index.cjs +1 -1
  344. package/dist/components/FileUploader/index.js +1 -1
  345. package/dist/components/Flag/index.cjs +1 -1
  346. package/dist/components/Flag/index.js +1 -1
  347. package/dist/components/FullscreenToggle/index.cjs +1 -1
  348. package/dist/components/FullscreenToggle/index.js +1 -1
  349. package/dist/components/Icon/index.cjs +1 -1
  350. package/dist/components/Icon/index.js +1 -1
  351. package/dist/components/IconButton/index.cjs +1 -1
  352. package/dist/components/IconButton/index.js +1 -1
  353. package/dist/components/ImageEditor/index.cjs +1 -1
  354. package/dist/components/ImageEditor/index.js +1 -1
  355. package/dist/components/List/index.cjs +1 -1
  356. package/dist/components/List/index.js +2 -2
  357. package/dist/components/Loader/index.cjs +1 -1
  358. package/dist/components/Loader/index.js +1 -1
  359. package/dist/components/LocationPicker/index.cjs +1 -1
  360. package/dist/components/LocationPicker/index.js +1 -1
  361. package/dist/components/Modal/index.cjs +1 -1
  362. package/dist/components/Modal/index.js +1 -1
  363. package/dist/components/MultiSelect/index.cjs +1 -1
  364. package/dist/components/MultiSelect/index.js +1 -1
  365. package/dist/components/NumberField/index.cjs +1 -1
  366. package/dist/components/NumberField/index.js +1 -1
  367. package/dist/components/OtpField/index.cjs +1 -1
  368. package/dist/components/OtpField/index.js +1 -1
  369. package/dist/components/PageError/index.cjs +1 -1
  370. package/dist/components/PageError/index.js +1 -1
  371. package/dist/components/PageLayout/index.cjs +1 -1
  372. package/dist/components/PageLayout/index.js +1 -1
  373. package/dist/components/PageNotFound/index.cjs +1 -1
  374. package/dist/components/PageNotFound/index.js +1 -1
  375. package/dist/components/Pagination/index.cjs +1 -1
  376. package/dist/components/Pagination/index.js +1 -1
  377. package/dist/components/PaletteField/index.cjs +1 -1
  378. package/dist/components/PaletteField/index.js +1 -1
  379. package/dist/components/PhoneField/index.cjs +1 -1
  380. package/dist/components/PhoneField/index.js +1 -1
  381. package/dist/components/Popconfirm/index.cjs +1 -1
  382. package/dist/components/Popconfirm/index.js +1 -1
  383. package/dist/components/Progress/index.cjs +1 -1
  384. package/dist/components/Progress/index.js +1 -1
  385. package/dist/components/QrCode/index.cjs +1 -1
  386. package/dist/components/QrCode/index.js +1 -1
  387. package/dist/components/RemoveDialog/index.cjs +1 -1
  388. package/dist/components/RemoveDialog/index.js +1 -1
  389. package/dist/components/RichTextEditor/index.cjs +1 -1
  390. package/dist/components/RichTextEditor/index.js +1 -1
  391. package/dist/components/RootLayout/index.cjs +1 -1
  392. package/dist/components/RootLayout/index.js +1 -1
  393. package/dist/components/Select/index.cjs +1 -1
  394. package/dist/components/Select/index.js +1 -1
  395. package/dist/components/Sidebar/Sidebar.d.cts +40 -4
  396. package/dist/components/Sidebar/Sidebar.d.ts +40 -4
  397. package/dist/components/Sidebar/index.cjs +1 -1
  398. package/dist/components/Sidebar/index.d.cts +2 -1
  399. package/dist/components/Sidebar/index.d.ts +2 -1
  400. package/dist/components/Sidebar/index.js +5 -4
  401. package/dist/components/Slider/index.cjs +1 -1
  402. package/dist/components/Slider/index.js +1 -1
  403. package/dist/components/SpeedDial/index.cjs +1 -1
  404. package/dist/components/SpeedDial/index.js +1 -1
  405. package/dist/components/Stepper/index.cjs +1 -1
  406. package/dist/components/Stepper/index.js +1 -1
  407. package/dist/components/SwatchPicker/index.cjs +1 -1
  408. package/dist/components/SwatchPicker/index.js +1 -1
  409. package/dist/components/Table/index.cjs +1 -1
  410. package/dist/components/Table/index.js +1 -1
  411. package/dist/components/Tabs/index.cjs +1 -1
  412. package/dist/components/Tabs/index.js +1 -1
  413. package/dist/components/TagsField/index.cjs +1 -1
  414. package/dist/components/TagsField/index.js +1 -1
  415. package/dist/components/TextField/index.cjs +1 -1
  416. package/dist/components/TextField/index.js +1 -1
  417. package/dist/components/ThemeToggle/index.cjs +1 -1
  418. package/dist/components/ThemeToggle/index.js +1 -1
  419. package/dist/components/TimePicker/index.cjs +1 -1
  420. package/dist/components/TimePicker/index.js +1 -1
  421. package/dist/components/Timeline/index.cjs +1 -1
  422. package/dist/components/Timeline/index.js +1 -1
  423. package/dist/components/Toast/index.cjs +1 -1
  424. package/dist/components/Toast/index.js +1 -1
  425. package/dist/components/ToggleButton/index.cjs +1 -1
  426. package/dist/components/ToggleButton/index.js +1 -1
  427. package/dist/components/TranslatedFields/index.cjs +1 -1
  428. package/dist/components/TranslatedFields/index.js +1 -1
  429. package/dist/components/UserCard/index.cjs +1 -1
  430. package/dist/components/UserCard/index.js +1 -1
  431. package/dist/entries/app.cjs +1 -1
  432. package/dist/entries/app.js +1 -1
  433. package/dist/entries/auth.cjs +1 -1
  434. package/dist/entries/auth.js +2 -2
  435. package/dist/entries/components.cjs +1 -1
  436. package/dist/entries/components.js +157 -156
  437. package/dist/entries/i18n.cjs +1 -1
  438. package/dist/entries/i18n.js +2 -2
  439. package/dist/entries/icons.cjs +1 -1
  440. package/dist/entries/icons.js +1 -1
  441. package/dist/entries/theme.cjs +1 -1
  442. package/dist/entries/theme.js +1 -1
  443. package/dist/i18n/messages.d.cts +4 -0
  444. package/dist/i18n/messages.d.ts +4 -0
  445. package/dist/index.cjs +1 -1
  446. package/dist/index.css +1 -1
  447. package/dist/index.js +173 -172
  448. package/dist/{messages-DeQuvGln.js → messages-CZbb1xNN.js} +29 -15
  449. package/dist/messages-CZbb1xNN.js.map +1 -0
  450. package/dist/messages-D4ooXnUr.cjs +36 -0
  451. package/dist/messages-D4ooXnUr.cjs.map +1 -0
  452. package/dist/useHomeTo---51HTJ0.cjs +2 -0
  453. package/dist/useHomeTo---51HTJ0.cjs.map +1 -0
  454. package/dist/useHomeTo-CJj94TdV.js +10 -0
  455. package/dist/useHomeTo-CJj94TdV.js.map +1 -0
  456. package/dist/{useOptionMenu-6ZffgbYG.cjs → useOptionMenu-DS___46k.cjs} +2 -2
  457. package/dist/{useOptionMenu-6ZffgbYG.cjs.map → useOptionMenu-DS___46k.cjs.map} +1 -1
  458. package/dist/{useOptionMenu-CxM6FHXL.js → useOptionMenu-Sp2d3Bzi.js} +6 -6
  459. package/dist/{useOptionMenu-CxM6FHXL.js.map → useOptionMenu-Sp2d3Bzi.js.map} +1 -1
  460. package/package.json +1 -1
  461. package/dist/AuthGuard-BTSRwF04.js +0 -108
  462. package/dist/AuthGuard-BTSRwF04.js.map +0 -1
  463. package/dist/AuthGuard-CLqroYbX.cjs +0 -2
  464. package/dist/AuthGuard-CLqroYbX.cjs.map +0 -1
  465. package/dist/Icon-B7DJn8Tw.js.map +0 -1
  466. package/dist/Icon-CBg21lKA.cjs +0 -2
  467. package/dist/Icon-CBg21lKA.cjs.map +0 -1
  468. package/dist/Sidebar-CLr-DyQ_.js +0 -522
  469. package/dist/Sidebar-CLr-DyQ_.js.map +0 -1
  470. package/dist/Sidebar-CM-jZfj5.cjs +0 -2
  471. package/dist/Sidebar-CM-jZfj5.cjs.map +0 -1
  472. package/dist/authLayoutRoute-AiQqIH85.cjs.map +0 -1
  473. package/dist/authLayoutRoute-Nf2PDNDN.js.map +0 -1
  474. package/dist/messages-DeQuvGln.js.map +0 -1
  475. package/dist/messages-dL9MkVze.cjs +0 -36
  476. package/dist/messages-dL9MkVze.cjs.map +0 -1
  477. package/dist/useHomeTo-BLSvhJd5.js +0 -25
  478. package/dist/useHomeTo-BLSvhJd5.js.map +0 -1
  479. package/dist/useHomeTo-cXCg1tf0.cjs +0 -2
  480. package/dist/useHomeTo-cXCg1tf0.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useOptionMenu-6ZffgbYG.cjs","sources":["../src/components/OptionMenu/OptionMenu.tsx","../src/components/OptionMenu/useOptionMenu.ts"],"sourcesContent":["import type { KeyboardEvent, ReactNode, RefObject } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { FloatingPanel } from '../FloatingPanel/FloatingPanel'\nimport { Icon } from '../Icon'\nimport { List, ListItem, type ListItemSize } from '../List'\nimport { Loader } from '../Loader'\nimport { Typography } from '../Typography'\nimport type { OptionMenuState, SelectOption } from './useOptionMenu'\nimport styles from './OptionMenu.module.css'\n\nexport interface OptionMenuProps {\n /** The state from `useOptionMenu`. */\n menu: OptionMenuState\n /** What the panel anchors under (and matches the width of) — also excluded from outside-click. */\n anchorRef: RefObject<HTMLElement | null>\n /** Row size. */\n size: ListItemSize\n /** Search box placeholder + accessible label. Defaults to the localized \"Search…\". */\n searchPlaceholder?: string\n /** Show a loader row instead of the options (server-side search in flight). */\n loading?: boolean\n /** Text next to the loader. Defaults to the localized \"Loading…\". */\n loadingText?: ReactNode\n /** Empty-result content — a node or `(query) => node`. Defaults to the localized \"No Options\". */\n noOptionsText?: ReactNode | ((query: string) => ReactNode)\n /** Tick the selected option(s). Defaults to `true`. */\n showSelectedTick?: boolean\n /** `aria-multiselectable` on the listbox. */\n multiselectable?: boolean\n /** Labels the listbox (the field label id). */\n labelledBy?: string\n /** Accessible label for the listbox when there's no visible label. */\n ariaLabel?: string\n /** Wraps the search box's key handling (e.g. MultiSelect's Backspace-removes-a-chip). */\n onSearchKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void\n /** Extra class on the panel. */\n className?: string\n}\n\n/**\n * The option popover shared by `Select`, `MultiSelect` and `PhoneField` (internal): a `FloatingPanel`\n * anchored under the field, an optional sticky search box (`role=\"combobox\"`, `aria-activedescendant`),\n * and a scrolling `role=\"listbox\"` of `ListItem` options — icon, label, the option's `trailing`, a tick\n * when selected, the keyboard highlight, disabled rows inert, `group`ed options under a labelled heading —\n * plus the loading and empty rows. All state\n * and keys live in `useOptionMenu`; this only renders it.\n */\nexport function OptionMenu({\n menu,\n anchorRef,\n size,\n searchPlaceholder,\n loading = false,\n loadingText,\n noOptionsText,\n showSelectedTick = true,\n multiselectable = false,\n labelledBy,\n ariaLabel,\n onSearchKeyDown,\n className,\n}: OptionMenuProps) {\n const t = useT()\n const searchPh = searchPlaceholder ?? t('common.search')\n const { filteredOptions, highlightedIndex } = menu\n\n const renderOption = ({ opt, index }: { opt: SelectOption; index: number }) => {\n const selected = menu.isSelected(opt)\n const tick = selected && showSelectedTick\n return (\n <ListItem\n key={opt.value}\n id={menu.optionId(index)}\n role=\"option\"\n tabIndex={-1}\n aria-selected={selected}\n aria-current={undefined}\n clickable\n selected={selected}\n disabled={opt.disabled}\n icon={opt.icon}\n className={clsx(index === highlightedIndex && styles.active)}\n trailing={\n opt.trailing != null || tick ? (\n <span className={styles.trailing}>\n {opt.trailing}\n {tick && <Icon name=\"TickCircle\" size=\"sm\" />}\n </span>\n ) : undefined\n }\n onMouseEnter={() => !opt.disabled && menu.setHighlightedIndex(index)}\n // keep focus where it is (trigger / search box) — a multi-select stays open and typing keeps\n // working; a single-select refocuses its trigger on close anyway\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => menu.pick(opt)}\n >\n {opt.label}\n </ListItem>\n )\n }\n\n // consecutive runs of the same `group` (the hook already gathered them) → a labelled role=\"group\"\n // each; ungrouped runs render as plain rows\n const renderRows = (rows: { opt: SelectOption; index: number }[]) => {\n if (!rows.some((r) => r.opt.group != null)) return rows.map(renderOption)\n const runs: { group: string | undefined; rows: typeof rows }[] = []\n for (const row of rows) {\n const last = runs[runs.length - 1]\n if (last && last.group === row.opt.group) last.rows.push(row)\n else runs.push({ group: row.opt.group, rows: [row] })\n }\n return runs.map((run, i) => {\n if (run.group == null) return run.rows.map(renderOption)\n const headingId = `${menu.listboxId}-group-${i}`\n return (\n <div key={`group-${i}`} role=\"group\" aria-labelledby={headingId} className={styles.group}>\n <Typography\n as=\"div\"\n id={headingId}\n role=\"presentation\"\n variant=\"caption\"\n color=\"muted\"\n uppercase\n className={styles.groupLabel}\n >\n {run.group}\n </Typography>\n {run.rows.map(renderOption)}\n </div>\n )\n })\n }\n\n return (\n <FloatingPanel\n ref={menu.popoverRef}\n open={menu.open}\n triggerRef={anchorRef}\n onClose={menu.closeMenu}\n matchTriggerWidth\n className={clsx(styles.popover, className)}\n >\n {menu.searchable && (\n <div className={styles.search}>\n <Icon name=\"SearchNormal\" size=\"sm\" className={styles.searchIcon} aria-hidden=\"true\" />\n <input\n ref={menu.searchInputRef}\n className={styles.searchInput}\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={menu.listboxId}\n aria-activedescendant={menu.activeId}\n aria-autocomplete=\"list\"\n aria-label={searchPh}\n placeholder={searchPh}\n value={menu.searchQuery}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => menu.setSearchQuery(e.target.value)}\n onKeyDown={onSearchKeyDown ?? menu.handleKeyDown}\n />\n </div>\n )}\n\n {/* the listbox always carries its id (even when empty) so aria-controls never dangles */}\n <List\n role=\"listbox\"\n id={menu.listboxId}\n aria-labelledby={labelledBy}\n aria-label={labelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiselectable || undefined}\n size={size}\n className={styles.listbox}\n // clear the mouse highlight when the pointer leaves the list (no lingering hover)\n onMouseLeave={() => menu.setHighlightedIndex(-1)}\n >\n {loading ? (\n <div className={styles.loading}>\n <Loader size=\"sm\" />\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {loadingText ?? t('common.loading')}\n </Typography>\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={styles.noOptions}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {noOptionsText == null\n ? t('select.noOptions')\n : typeof noOptionsText === 'function'\n ? noOptionsText(menu.searchQuery)\n : noOptionsText}\n </Typography>\n </div>\n ) : (\n renderRows(filteredOptions.map((opt, index) => ({ opt, index })))\n )}\n </List>\n </FloatingPanel>\n )\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type RefObject,\n} from 'react'\nimport type { ReactNode } from 'react'\nimport type { IconName } from '../../icons/names'\n\n/** A single selectable option — shared by `Select`, `MultiSelect` and `PhoneField`. */\nexport interface SelectOption {\n /** The value committed when this option is chosen. */\n value: string\n /** Display + search text. */\n label: string\n /** Greys out and blocks selecting this option. */\n disabled?: boolean\n /** Leading icon — a known `IconName` (rendered as `<Icon>`) or any node. */\n icon?: IconName | ReactNode\n /**\n * Extra search terms matched alongside the label (case-insensitive, substring) — e.g. a currency's\n * code (`'USD'`) or a country's calling code (`'995'`). Never shown.\n */\n keywords?: readonly string[]\n /** Content on the right of the row, before the selected tick (e.g. a code or a count). */\n trailing?: ReactNode\n /**\n * Group heading. Options sharing a `group` are listed together under it (groups in order of first\n * appearance, options keeping their order within a group); options without one stay ungrouped.\n */\n group?: string\n}\n\n/**\n * Stable-group the options: each group gathered at its first appearance, order kept within a group. A\n * list with no `group` at all is returned untouched (the common case costs nothing).\n */\nexport function groupOptions<T extends SelectOption>(options: readonly T[]): readonly T[] {\n if (!options.some((o) => o.group != null)) return options\n const buckets = new Map<string | undefined, T[]>()\n for (const o of options) {\n const bucket = buckets.get(o.group)\n if (bucket) bucket.push(o)\n else buckets.set(o.group, [o])\n }\n return [...buckets.values()].flat()\n}\n\nexport interface UseOptionMenuOptions {\n /** Base for the listbox / option ids (`${idBase}-listbox`, `${idBase}-opt-${i}`). */\n idBase: string\n options: readonly SelectOption[]\n /** Whether an option is selected (drives the initial highlight when `highlightSelected`). */\n isSelected: (option: SelectOption) => boolean\n /** Called when an option is picked (Enter / Space / click). */\n onPick: (option: SelectOption) => void\n /** Close the menu after a pick (single-select) or keep it open (multi-select). Defaults to `true`. */\n closeOnPick?: boolean\n /** On open, highlight the selected option (single-select) instead of the first. Defaults to `true`. */\n highlightSelected?: boolean\n /** Show a search box that filters by label + keywords. */\n searchable?: boolean\n /** The consumer filters `options` itself (server-side search) — skip the local filter. */\n onSearchChange?: (query: string) => void\n disabled?: boolean\n /** The element focus returns to when the menu closes with `refocus` (the trigger / the input). */\n focusRef: RefObject<HTMLElement | null>\n /** Runs on every close (e.g. mark a form field touched). */\n onClose?: () => void\n}\n\n/**\n * The state + keyboard model behind every option popover (internal): open / close, the search query\n * and its label + keywords filter, the highlighted row (skipping disabled ones), type-ahead when not\n * searchable, and one `handleKeyDown` for the trigger and the search box — Arrow / Home / End move,\n * Enter / Space pick, Escape closes (refocusing), Tab closes and moves on. Render it with `OptionMenu`.\n */\nexport function useOptionMenu({\n idBase,\n options,\n isSelected,\n onPick,\n closeOnPick = true,\n highlightSelected = true,\n searchable = false,\n onSearchChange,\n disabled = false,\n focusRef,\n onClose,\n}: UseOptionMenuOptions) {\n const listboxId = `${idBase}-listbox`\n const optionId = useCallback((index: number) => `${idBase}-opt-${index}`, [idBase])\n\n const [open, setOpen] = useState(false)\n const [searchQuery, setSearchQueryState] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const searchInputRef = useRef<HTMLInputElement | null>(null)\n // the floating panel forwards its node here, for the focus-leaves-the-widget check on blur\n const popoverRef = useRef<HTMLDivElement | null>(null)\n const typeahead = useRef({ buffer: '', timer: 0 })\n // latest callbacks without re-creating the stable handlers\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n // local filter by label + keywords (skipped when the consumer owns the options — server search), then\n // grouped, so the flat index the keyboard walks is exactly the rendered order\n const filteredOptions = useMemo(() => {\n const q = searchQuery.trim().toLowerCase()\n const matches =\n !searchable || onSearchChange || !q\n ? options\n : options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.keywords?.some((k) => k.toLowerCase().includes(q)),\n )\n return groupOptions(matches)\n }, [searchable, onSearchChange, searchQuery, options])\n\n const findEnabled = useCallback(\n (start: number, delta: number) => {\n let i = start\n while (i >= 0 && i < filteredOptions.length) {\n if (!filteredOptions[i].disabled) return i\n i += delta\n }\n return -1\n },\n [filteredOptions],\n )\n\n // single dismiss path: clears the search + type-ahead, notifies, optionally refocuses\n const closeMenu = useCallback(\n (refocus: boolean) => {\n setOpen(false)\n setSearchQueryState('')\n window.clearTimeout(typeahead.current.timer)\n typeahead.current.buffer = ''\n onCloseRef.current?.()\n if (refocus) focusRef.current?.focus()\n },\n [focusRef],\n )\n\n // on open: highlight the selected option (or the first enabled), focus the search box\n useEffect(() => {\n if (!open) return\n const selIdx = highlightSelected ? filteredOptions.findIndex(isSelected) : -1\n setHighlightedIndex(\n selIdx >= 0 && !filteredOptions[selIdx].disabled ? selIdx : findEnabled(0, 1),\n )\n if (searchable) requestAnimationFrame(() => searchInputRef.current?.focus())\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n // keep the highlighted option scrolled into view\n useEffect(() => {\n if (!open || highlightedIndex < 0) return\n document.getElementById(optionId(highlightedIndex))?.scrollIntoView?.({ block: 'nearest' })\n }, [open, highlightedIndex, optionId])\n\n // a new search → re-anchor the highlight to the first match\n useEffect(() => {\n if (open && searchable) setHighlightedIndex(findEnabled(0, 1))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [searchQuery])\n\n // the option count changed while open (async load / list shrink) → keep the highlight in range\n useEffect(() => {\n if (open) setHighlightedIndex((i) => (i < filteredOptions.length ? i : findEnabled(0, 1)))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filteredOptions.length])\n\n const openMenu = () => {\n if (!disabled) setOpen(true)\n }\n const toggleMenu = () => (open ? closeMenu(false) : openMenu())\n\n const setSearchQuery = (query: string) => {\n setSearchQueryState(query)\n onSearchChange?.(query)\n }\n\n const pick = (option: SelectOption | undefined) => {\n if (!option || option.disabled) return\n onPick(option)\n if (closeOnPick) closeMenu(true)\n }\n\n const moveHighlight = (delta: number) => {\n setHighlightedIndex((cur) => {\n const start = cur < 0 ? (delta > 0 ? 0 : filteredOptions.length - 1) : cur + delta\n const found = findEnabled(start, delta)\n return found === -1 ? cur : found\n })\n }\n\n // type-ahead (no search box): jump to the option whose label starts with the typed buffer\n const handleTypeahead = (char: string) => {\n const t = typeahead.current\n window.clearTimeout(t.timer)\n t.buffer += char.toLowerCase()\n t.timer = window.setTimeout(() => (t.buffer = ''), 500)\n const match = filteredOptions.findIndex(\n (o) => !o.disabled && o.label.toLowerCase().startsWith(t.buffer),\n )\n if (match >= 0) setHighlightedIndex(match)\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (disabled) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n open ? moveHighlight(1) : openMenu()\n break\n case 'ArrowUp':\n event.preventDefault()\n open ? moveHighlight(-1) : openMenu()\n break\n case 'Enter':\n event.preventDefault()\n if (!open) openMenu()\n else pick(filteredOptions[highlightedIndex])\n break\n case ' ':\n // Space opens a closed menu; picks only when open without a search box (so search can type spaces)\n if (!open) {\n event.preventDefault()\n openMenu()\n } else if (!searchable) {\n event.preventDefault()\n pick(filteredOptions[highlightedIndex])\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation() // don't let FloatingPanel's own Escape also fire closeMenu\n closeMenu(true)\n }\n break\n case 'Tab':\n // refocus the trigger so Tab continues from the field's visual spot, not the portaled search\n // input's DOM position (end of <body>); no preventDefault — let Tab move on\n if (open) closeMenu(true)\n break\n case 'Home':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(0, 1))\n }\n break\n case 'End':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(filteredOptions.length - 1, -1))\n }\n break\n default:\n if (\n !searchable &&\n open &&\n event.key.length === 1 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.altKey\n ) {\n handleTypeahead(event.key)\n }\n }\n }\n\n const activeId = open && highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined\n\n return {\n open,\n openMenu,\n closeMenu,\n toggleMenu,\n searchable,\n searchQuery,\n setSearchQuery,\n filteredOptions,\n highlightedIndex,\n setHighlightedIndex,\n isSelected,\n pick,\n handleKeyDown,\n listboxId,\n optionId,\n activeId,\n searchInputRef,\n popoverRef,\n }\n}\n\n/** Everything `useOptionMenu` returns — pass it to `<OptionMenu menu={…} />`. */\nexport type OptionMenuState = ReturnType<typeof useOptionMenu>\n"],"names":["OptionMenu","menu","anchorRef","size","searchPlaceholder","loading","loadingText","noOptionsText","showSelectedTick","multiselectable","labelledBy","ariaLabel","onSearchKeyDown","className","t","useT","searchPh","filteredOptions","highlightedIndex","renderOption","opt","index","selected","tick","jsx","ListItem","clsx","styles","jsxs","Icon","e","renderRows","rows","r","runs","row","last","run","i","headingId","Typography","FloatingPanel","List","Loader","groupOptions","options","o","buckets","bucket","useOptionMenu","idBase","isSelected","onPick","closeOnPick","highlightSelected","searchable","onSearchChange","disabled","focusRef","onClose","listboxId","optionId","useCallback","open","setOpen","useState","searchQuery","setSearchQueryState","setHighlightedIndex","searchInputRef","useRef","popoverRef","typeahead","onCloseRef","useMemo","q","matches","_a","k","findEnabled","start","delta","closeMenu","refocus","_b","useEffect","selIdx","openMenu","toggleMenu","setSearchQuery","query","pick","option","moveHighlight","cur","found","handleTypeahead","char","match","handleKeyDown","event","activeId"],"mappings":"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"}
1
+ {"version":3,"file":"useOptionMenu-DS___46k.cjs","sources":["../src/components/OptionMenu/OptionMenu.tsx","../src/components/OptionMenu/useOptionMenu.ts"],"sourcesContent":["import type { KeyboardEvent, ReactNode, RefObject } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { FloatingPanel } from '../FloatingPanel/FloatingPanel'\nimport { Icon } from '../Icon'\nimport { List, ListItem, type ListItemSize } from '../List'\nimport { Loader } from '../Loader'\nimport { Typography } from '../Typography'\nimport type { OptionMenuState, SelectOption } from './useOptionMenu'\nimport styles from './OptionMenu.module.css'\n\nexport interface OptionMenuProps {\n /** The state from `useOptionMenu`. */\n menu: OptionMenuState\n /** What the panel anchors under (and matches the width of) — also excluded from outside-click. */\n anchorRef: RefObject<HTMLElement | null>\n /** Row size. */\n size: ListItemSize\n /** Search box placeholder + accessible label. Defaults to the localized \"Search…\". */\n searchPlaceholder?: string\n /** Show a loader row instead of the options (server-side search in flight). */\n loading?: boolean\n /** Text next to the loader. Defaults to the localized \"Loading…\". */\n loadingText?: ReactNode\n /** Empty-result content — a node or `(query) => node`. Defaults to the localized \"No Options\". */\n noOptionsText?: ReactNode | ((query: string) => ReactNode)\n /** Tick the selected option(s). Defaults to `true`. */\n showSelectedTick?: boolean\n /** `aria-multiselectable` on the listbox. */\n multiselectable?: boolean\n /** Labels the listbox (the field label id). */\n labelledBy?: string\n /** Accessible label for the listbox when there's no visible label. */\n ariaLabel?: string\n /** Wraps the search box's key handling (e.g. MultiSelect's Backspace-removes-a-chip). */\n onSearchKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void\n /** Extra class on the panel. */\n className?: string\n}\n\n/**\n * The option popover shared by `Select`, `MultiSelect` and `PhoneField` (internal): a `FloatingPanel`\n * anchored under the field, an optional sticky search box (`role=\"combobox\"`, `aria-activedescendant`),\n * and a scrolling `role=\"listbox\"` of `ListItem` options — icon, label, the option's `trailing`, a tick\n * when selected, the keyboard highlight, disabled rows inert, `group`ed options under a labelled heading —\n * plus the loading and empty rows. All state\n * and keys live in `useOptionMenu`; this only renders it.\n */\nexport function OptionMenu({\n menu,\n anchorRef,\n size,\n searchPlaceholder,\n loading = false,\n loadingText,\n noOptionsText,\n showSelectedTick = true,\n multiselectable = false,\n labelledBy,\n ariaLabel,\n onSearchKeyDown,\n className,\n}: OptionMenuProps) {\n const t = useT()\n const searchPh = searchPlaceholder ?? t('common.search')\n const { filteredOptions, highlightedIndex } = menu\n\n const renderOption = ({ opt, index }: { opt: SelectOption; index: number }) => {\n const selected = menu.isSelected(opt)\n const tick = selected && showSelectedTick\n return (\n <ListItem\n key={opt.value}\n id={menu.optionId(index)}\n role=\"option\"\n tabIndex={-1}\n aria-selected={selected}\n aria-current={undefined}\n clickable\n selected={selected}\n disabled={opt.disabled}\n icon={opt.icon}\n className={clsx(index === highlightedIndex && styles.active)}\n trailing={\n opt.trailing != null || tick ? (\n <span className={styles.trailing}>\n {opt.trailing}\n {tick && <Icon name=\"TickCircle\" size=\"sm\" />}\n </span>\n ) : undefined\n }\n onMouseEnter={() => !opt.disabled && menu.setHighlightedIndex(index)}\n // keep focus where it is (trigger / search box) — a multi-select stays open and typing keeps\n // working; a single-select refocuses its trigger on close anyway\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => menu.pick(opt)}\n >\n {opt.label}\n </ListItem>\n )\n }\n\n // consecutive runs of the same `group` (the hook already gathered them) → a labelled role=\"group\"\n // each; ungrouped runs render as plain rows\n const renderRows = (rows: { opt: SelectOption; index: number }[]) => {\n if (!rows.some((r) => r.opt.group != null)) return rows.map(renderOption)\n const runs: { group: string | undefined; rows: typeof rows }[] = []\n for (const row of rows) {\n const last = runs[runs.length - 1]\n if (last && last.group === row.opt.group) last.rows.push(row)\n else runs.push({ group: row.opt.group, rows: [row] })\n }\n return runs.map((run, i) => {\n if (run.group == null) return run.rows.map(renderOption)\n const headingId = `${menu.listboxId}-group-${i}`\n return (\n <div key={`group-${i}`} role=\"group\" aria-labelledby={headingId} className={styles.group}>\n <Typography\n as=\"div\"\n id={headingId}\n role=\"presentation\"\n variant=\"caption\"\n color=\"muted\"\n uppercase\n className={styles.groupLabel}\n >\n {run.group}\n </Typography>\n {run.rows.map(renderOption)}\n </div>\n )\n })\n }\n\n return (\n <FloatingPanel\n ref={menu.popoverRef}\n open={menu.open}\n triggerRef={anchorRef}\n onClose={menu.closeMenu}\n matchTriggerWidth\n className={clsx(styles.popover, className)}\n >\n {menu.searchable && (\n <div className={styles.search}>\n <Icon name=\"SearchNormal\" size=\"sm\" className={styles.searchIcon} aria-hidden=\"true\" />\n <input\n ref={menu.searchInputRef}\n className={styles.searchInput}\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={menu.listboxId}\n aria-activedescendant={menu.activeId}\n aria-autocomplete=\"list\"\n aria-label={searchPh}\n placeholder={searchPh}\n value={menu.searchQuery}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => menu.setSearchQuery(e.target.value)}\n onKeyDown={onSearchKeyDown ?? menu.handleKeyDown}\n />\n </div>\n )}\n\n {/* the listbox always carries its id (even when empty) so aria-controls never dangles */}\n <List\n role=\"listbox\"\n id={menu.listboxId}\n aria-labelledby={labelledBy}\n aria-label={labelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiselectable || undefined}\n size={size}\n className={styles.listbox}\n // clear the mouse highlight when the pointer leaves the list (no lingering hover)\n onMouseLeave={() => menu.setHighlightedIndex(-1)}\n >\n {loading ? (\n <div className={styles.loading}>\n <Loader size=\"sm\" />\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {loadingText ?? t('common.loading')}\n </Typography>\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={styles.noOptions}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {noOptionsText == null\n ? t('select.noOptions')\n : typeof noOptionsText === 'function'\n ? noOptionsText(menu.searchQuery)\n : noOptionsText}\n </Typography>\n </div>\n ) : (\n renderRows(filteredOptions.map((opt, index) => ({ opt, index })))\n )}\n </List>\n </FloatingPanel>\n )\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type RefObject,\n} from 'react'\nimport type { ReactNode } from 'react'\nimport type { IconName } from '../../icons/names'\n\n/** A single selectable option — shared by `Select`, `MultiSelect` and `PhoneField`. */\nexport interface SelectOption {\n /** The value committed when this option is chosen. */\n value: string\n /** Display + search text. */\n label: string\n /** Greys out and blocks selecting this option. */\n disabled?: boolean\n /** Leading icon — a known `IconName` (rendered as `<Icon>`) or any node. */\n icon?: IconName | ReactNode\n /**\n * Extra search terms matched alongside the label (case-insensitive, substring) — e.g. a currency's\n * code (`'USD'`) or a country's calling code (`'995'`). Never shown.\n */\n keywords?: readonly string[]\n /** Content on the right of the row, before the selected tick (e.g. a code or a count). */\n trailing?: ReactNode\n /**\n * Group heading. Options sharing a `group` are listed together under it (groups in order of first\n * appearance, options keeping their order within a group); options without one stay ungrouped.\n */\n group?: string\n}\n\n/**\n * Stable-group the options: each group gathered at its first appearance, order kept within a group. A\n * list with no `group` at all is returned untouched (the common case costs nothing).\n */\nexport function groupOptions<T extends SelectOption>(options: readonly T[]): readonly T[] {\n if (!options.some((o) => o.group != null)) return options\n const buckets = new Map<string | undefined, T[]>()\n for (const o of options) {\n const bucket = buckets.get(o.group)\n if (bucket) bucket.push(o)\n else buckets.set(o.group, [o])\n }\n return [...buckets.values()].flat()\n}\n\nexport interface UseOptionMenuOptions {\n /** Base for the listbox / option ids (`${idBase}-listbox`, `${idBase}-opt-${i}`). */\n idBase: string\n options: readonly SelectOption[]\n /** Whether an option is selected (drives the initial highlight when `highlightSelected`). */\n isSelected: (option: SelectOption) => boolean\n /** Called when an option is picked (Enter / Space / click). */\n onPick: (option: SelectOption) => void\n /** Close the menu after a pick (single-select) or keep it open (multi-select). Defaults to `true`. */\n closeOnPick?: boolean\n /** On open, highlight the selected option (single-select) instead of the first. Defaults to `true`. */\n highlightSelected?: boolean\n /** Show a search box that filters by label + keywords. */\n searchable?: boolean\n /** The consumer filters `options` itself (server-side search) — skip the local filter. */\n onSearchChange?: (query: string) => void\n disabled?: boolean\n /** The element focus returns to when the menu closes with `refocus` (the trigger / the input). */\n focusRef: RefObject<HTMLElement | null>\n /** Runs on every close (e.g. mark a form field touched). */\n onClose?: () => void\n}\n\n/**\n * The state + keyboard model behind every option popover (internal): open / close, the search query\n * and its label + keywords filter, the highlighted row (skipping disabled ones), type-ahead when not\n * searchable, and one `handleKeyDown` for the trigger and the search box — Arrow / Home / End move,\n * Enter / Space pick, Escape closes (refocusing), Tab closes and moves on. Render it with `OptionMenu`.\n */\nexport function useOptionMenu({\n idBase,\n options,\n isSelected,\n onPick,\n closeOnPick = true,\n highlightSelected = true,\n searchable = false,\n onSearchChange,\n disabled = false,\n focusRef,\n onClose,\n}: UseOptionMenuOptions) {\n const listboxId = `${idBase}-listbox`\n const optionId = useCallback((index: number) => `${idBase}-opt-${index}`, [idBase])\n\n const [open, setOpen] = useState(false)\n const [searchQuery, setSearchQueryState] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const searchInputRef = useRef<HTMLInputElement | null>(null)\n // the floating panel forwards its node here, for the focus-leaves-the-widget check on blur\n const popoverRef = useRef<HTMLDivElement | null>(null)\n const typeahead = useRef({ buffer: '', timer: 0 })\n // latest callbacks without re-creating the stable handlers\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n // local filter by label + keywords (skipped when the consumer owns the options — server search), then\n // grouped, so the flat index the keyboard walks is exactly the rendered order\n const filteredOptions = useMemo(() => {\n const q = searchQuery.trim().toLowerCase()\n const matches =\n !searchable || onSearchChange || !q\n ? options\n : options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.keywords?.some((k) => k.toLowerCase().includes(q)),\n )\n return groupOptions(matches)\n }, [searchable, onSearchChange, searchQuery, options])\n\n const findEnabled = useCallback(\n (start: number, delta: number) => {\n let i = start\n while (i >= 0 && i < filteredOptions.length) {\n if (!filteredOptions[i].disabled) return i\n i += delta\n }\n return -1\n },\n [filteredOptions],\n )\n\n // single dismiss path: clears the search + type-ahead, notifies, optionally refocuses\n const closeMenu = useCallback(\n (refocus: boolean) => {\n setOpen(false)\n setSearchQueryState('')\n window.clearTimeout(typeahead.current.timer)\n typeahead.current.buffer = ''\n onCloseRef.current?.()\n if (refocus) focusRef.current?.focus()\n },\n [focusRef],\n )\n\n // on open: highlight the selected option (or the first enabled), focus the search box\n useEffect(() => {\n if (!open) return\n const selIdx = highlightSelected ? filteredOptions.findIndex(isSelected) : -1\n setHighlightedIndex(\n selIdx >= 0 && !filteredOptions[selIdx].disabled ? selIdx : findEnabled(0, 1),\n )\n if (searchable) requestAnimationFrame(() => searchInputRef.current?.focus())\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n // keep the highlighted option scrolled into view\n useEffect(() => {\n if (!open || highlightedIndex < 0) return\n document.getElementById(optionId(highlightedIndex))?.scrollIntoView?.({ block: 'nearest' })\n }, [open, highlightedIndex, optionId])\n\n // a new search → re-anchor the highlight to the first match\n useEffect(() => {\n if (open && searchable) setHighlightedIndex(findEnabled(0, 1))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [searchQuery])\n\n // the option count changed while open (async load / list shrink) → keep the highlight in range\n useEffect(() => {\n if (open) setHighlightedIndex((i) => (i < filteredOptions.length ? i : findEnabled(0, 1)))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filteredOptions.length])\n\n const openMenu = () => {\n if (!disabled) setOpen(true)\n }\n const toggleMenu = () => (open ? closeMenu(false) : openMenu())\n\n const setSearchQuery = (query: string) => {\n setSearchQueryState(query)\n onSearchChange?.(query)\n }\n\n const pick = (option: SelectOption | undefined) => {\n if (!option || option.disabled) return\n onPick(option)\n if (closeOnPick) closeMenu(true)\n }\n\n const moveHighlight = (delta: number) => {\n setHighlightedIndex((cur) => {\n const start = cur < 0 ? (delta > 0 ? 0 : filteredOptions.length - 1) : cur + delta\n const found = findEnabled(start, delta)\n return found === -1 ? cur : found\n })\n }\n\n // type-ahead (no search box): jump to the option whose label starts with the typed buffer\n const handleTypeahead = (char: string) => {\n const t = typeahead.current\n window.clearTimeout(t.timer)\n t.buffer += char.toLowerCase()\n t.timer = window.setTimeout(() => (t.buffer = ''), 500)\n const match = filteredOptions.findIndex(\n (o) => !o.disabled && o.label.toLowerCase().startsWith(t.buffer),\n )\n if (match >= 0) setHighlightedIndex(match)\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (disabled) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n open ? moveHighlight(1) : openMenu()\n break\n case 'ArrowUp':\n event.preventDefault()\n open ? moveHighlight(-1) : openMenu()\n break\n case 'Enter':\n event.preventDefault()\n if (!open) openMenu()\n else pick(filteredOptions[highlightedIndex])\n break\n case ' ':\n // Space opens a closed menu; picks only when open without a search box (so search can type spaces)\n if (!open) {\n event.preventDefault()\n openMenu()\n } else if (!searchable) {\n event.preventDefault()\n pick(filteredOptions[highlightedIndex])\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation() // don't let FloatingPanel's own Escape also fire closeMenu\n closeMenu(true)\n }\n break\n case 'Tab':\n // refocus the trigger so Tab continues from the field's visual spot, not the portaled search\n // input's DOM position (end of <body>); no preventDefault — let Tab move on\n if (open) closeMenu(true)\n break\n case 'Home':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(0, 1))\n }\n break\n case 'End':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(filteredOptions.length - 1, -1))\n }\n break\n default:\n if (\n !searchable &&\n open &&\n event.key.length === 1 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.altKey\n ) {\n handleTypeahead(event.key)\n }\n }\n }\n\n const activeId = open && highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined\n\n return {\n open,\n openMenu,\n closeMenu,\n toggleMenu,\n searchable,\n searchQuery,\n setSearchQuery,\n filteredOptions,\n highlightedIndex,\n setHighlightedIndex,\n isSelected,\n pick,\n handleKeyDown,\n listboxId,\n optionId,\n activeId,\n searchInputRef,\n popoverRef,\n }\n}\n\n/** Everything `useOptionMenu` returns — pass it to `<OptionMenu menu={…} />`. */\nexport type OptionMenuState = ReturnType<typeof useOptionMenu>\n"],"names":["OptionMenu","menu","anchorRef","size","searchPlaceholder","loading","loadingText","noOptionsText","showSelectedTick","multiselectable","labelledBy","ariaLabel","onSearchKeyDown","className","t","useT","searchPh","filteredOptions","highlightedIndex","renderOption","opt","index","selected","tick","jsx","ListItem","clsx","styles","jsxs","Icon","e","renderRows","rows","r","runs","row","last","run","i","headingId","Typography","FloatingPanel","List","Loader","groupOptions","options","o","buckets","bucket","useOptionMenu","idBase","isSelected","onPick","closeOnPick","highlightSelected","searchable","onSearchChange","disabled","focusRef","onClose","listboxId","optionId","useCallback","open","setOpen","useState","searchQuery","setSearchQueryState","setHighlightedIndex","searchInputRef","useRef","popoverRef","typeahead","onCloseRef","useMemo","q","matches","_a","k","findEnabled","start","delta","closeMenu","refocus","_b","useEffect","selIdx","openMenu","toggleMenu","setSearchQuery","query","pick","option","moveHighlight","cur","found","handleTypeahead","char","match","handleKeyDown","event","activeId"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  import { jsxs as N, jsx as h } from "react/jsx-runtime";
2
2
  import { clsx as P } from "clsx";
3
3
  import { F as J } from "./FloatingPanel-C5c_eMQ0.js";
4
- import { b as j } from "./Icon-B7DJn8Tw.js";
5
- import { L as X } from "./List-DS91CZUt.js";
6
- import { L as Y } from "./ListItem-Ezmdk7q-.js";
7
- import { L as Z } from "./Loader-DD1vfqmN.js";
4
+ import { b as j } from "./Icon-DMMO32p6.js";
5
+ import { L as X } from "./List-DQlEG_S5.js";
6
+ import { L as Y } from "./ListItem-CLmg9xKQ.js";
7
+ import { L as Z } from "./Loader-CShIWNfG.js";
8
8
  import { T as C } from "./Typography-ChSuxgkc.js";
9
- import { a as B } from "./ConfigProvider-DtyUlWk6.js";
9
+ import { a as B } from "./ConfigProvider-bXX8dnhY.js";
10
10
  import { useCallback as z, useState as A, useRef as T, useMemo as ee, useEffect as K } from "react";
11
11
  const re = "_popover_rf9kn_3", te = "_search_rf9kn_11", oe = "_searchIcon_rf9kn_20", se = "_searchInput_rf9kn_24", ae = "_listbox_rf9kn_40", ne = "_active_rf9kn_48", ie = "_noOptions_rf9kn_52", le = "_loading_rf9kn_58", ce = "_group_rf9kn_68", ue = "_groupLabel_rf9kn_80", fe = "_trailing_rf9kn_86", p = {
12
12
  popover: re,
@@ -284,4 +284,4 @@ export {
284
284
  ye as O,
285
285
  xe as u
286
286
  };
287
- //# sourceMappingURL=useOptionMenu-CxM6FHXL.js.map
287
+ //# sourceMappingURL=useOptionMenu-Sp2d3Bzi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOptionMenu-CxM6FHXL.js","sources":["../src/components/OptionMenu/OptionMenu.tsx","../src/components/OptionMenu/useOptionMenu.ts"],"sourcesContent":["import type { KeyboardEvent, ReactNode, RefObject } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { FloatingPanel } from '../FloatingPanel/FloatingPanel'\nimport { Icon } from '../Icon'\nimport { List, ListItem, type ListItemSize } from '../List'\nimport { Loader } from '../Loader'\nimport { Typography } from '../Typography'\nimport type { OptionMenuState, SelectOption } from './useOptionMenu'\nimport styles from './OptionMenu.module.css'\n\nexport interface OptionMenuProps {\n /** The state from `useOptionMenu`. */\n menu: OptionMenuState\n /** What the panel anchors under (and matches the width of) — also excluded from outside-click. */\n anchorRef: RefObject<HTMLElement | null>\n /** Row size. */\n size: ListItemSize\n /** Search box placeholder + accessible label. Defaults to the localized \"Search…\". */\n searchPlaceholder?: string\n /** Show a loader row instead of the options (server-side search in flight). */\n loading?: boolean\n /** Text next to the loader. Defaults to the localized \"Loading…\". */\n loadingText?: ReactNode\n /** Empty-result content — a node or `(query) => node`. Defaults to the localized \"No Options\". */\n noOptionsText?: ReactNode | ((query: string) => ReactNode)\n /** Tick the selected option(s). Defaults to `true`. */\n showSelectedTick?: boolean\n /** `aria-multiselectable` on the listbox. */\n multiselectable?: boolean\n /** Labels the listbox (the field label id). */\n labelledBy?: string\n /** Accessible label for the listbox when there's no visible label. */\n ariaLabel?: string\n /** Wraps the search box's key handling (e.g. MultiSelect's Backspace-removes-a-chip). */\n onSearchKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void\n /** Extra class on the panel. */\n className?: string\n}\n\n/**\n * The option popover shared by `Select`, `MultiSelect` and `PhoneField` (internal): a `FloatingPanel`\n * anchored under the field, an optional sticky search box (`role=\"combobox\"`, `aria-activedescendant`),\n * and a scrolling `role=\"listbox\"` of `ListItem` options — icon, label, the option's `trailing`, a tick\n * when selected, the keyboard highlight, disabled rows inert, `group`ed options under a labelled heading —\n * plus the loading and empty rows. All state\n * and keys live in `useOptionMenu`; this only renders it.\n */\nexport function OptionMenu({\n menu,\n anchorRef,\n size,\n searchPlaceholder,\n loading = false,\n loadingText,\n noOptionsText,\n showSelectedTick = true,\n multiselectable = false,\n labelledBy,\n ariaLabel,\n onSearchKeyDown,\n className,\n}: OptionMenuProps) {\n const t = useT()\n const searchPh = searchPlaceholder ?? t('common.search')\n const { filteredOptions, highlightedIndex } = menu\n\n const renderOption = ({ opt, index }: { opt: SelectOption; index: number }) => {\n const selected = menu.isSelected(opt)\n const tick = selected && showSelectedTick\n return (\n <ListItem\n key={opt.value}\n id={menu.optionId(index)}\n role=\"option\"\n tabIndex={-1}\n aria-selected={selected}\n aria-current={undefined}\n clickable\n selected={selected}\n disabled={opt.disabled}\n icon={opt.icon}\n className={clsx(index === highlightedIndex && styles.active)}\n trailing={\n opt.trailing != null || tick ? (\n <span className={styles.trailing}>\n {opt.trailing}\n {tick && <Icon name=\"TickCircle\" size=\"sm\" />}\n </span>\n ) : undefined\n }\n onMouseEnter={() => !opt.disabled && menu.setHighlightedIndex(index)}\n // keep focus where it is (trigger / search box) — a multi-select stays open and typing keeps\n // working; a single-select refocuses its trigger on close anyway\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => menu.pick(opt)}\n >\n {opt.label}\n </ListItem>\n )\n }\n\n // consecutive runs of the same `group` (the hook already gathered them) → a labelled role=\"group\"\n // each; ungrouped runs render as plain rows\n const renderRows = (rows: { opt: SelectOption; index: number }[]) => {\n if (!rows.some((r) => r.opt.group != null)) return rows.map(renderOption)\n const runs: { group: string | undefined; rows: typeof rows }[] = []\n for (const row of rows) {\n const last = runs[runs.length - 1]\n if (last && last.group === row.opt.group) last.rows.push(row)\n else runs.push({ group: row.opt.group, rows: [row] })\n }\n return runs.map((run, i) => {\n if (run.group == null) return run.rows.map(renderOption)\n const headingId = `${menu.listboxId}-group-${i}`\n return (\n <div key={`group-${i}`} role=\"group\" aria-labelledby={headingId} className={styles.group}>\n <Typography\n as=\"div\"\n id={headingId}\n role=\"presentation\"\n variant=\"caption\"\n color=\"muted\"\n uppercase\n className={styles.groupLabel}\n >\n {run.group}\n </Typography>\n {run.rows.map(renderOption)}\n </div>\n )\n })\n }\n\n return (\n <FloatingPanel\n ref={menu.popoverRef}\n open={menu.open}\n triggerRef={anchorRef}\n onClose={menu.closeMenu}\n matchTriggerWidth\n className={clsx(styles.popover, className)}\n >\n {menu.searchable && (\n <div className={styles.search}>\n <Icon name=\"SearchNormal\" size=\"sm\" className={styles.searchIcon} aria-hidden=\"true\" />\n <input\n ref={menu.searchInputRef}\n className={styles.searchInput}\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={menu.listboxId}\n aria-activedescendant={menu.activeId}\n aria-autocomplete=\"list\"\n aria-label={searchPh}\n placeholder={searchPh}\n value={menu.searchQuery}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => menu.setSearchQuery(e.target.value)}\n onKeyDown={onSearchKeyDown ?? menu.handleKeyDown}\n />\n </div>\n )}\n\n {/* the listbox always carries its id (even when empty) so aria-controls never dangles */}\n <List\n role=\"listbox\"\n id={menu.listboxId}\n aria-labelledby={labelledBy}\n aria-label={labelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiselectable || undefined}\n size={size}\n className={styles.listbox}\n // clear the mouse highlight when the pointer leaves the list (no lingering hover)\n onMouseLeave={() => menu.setHighlightedIndex(-1)}\n >\n {loading ? (\n <div className={styles.loading}>\n <Loader size=\"sm\" />\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {loadingText ?? t('common.loading')}\n </Typography>\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={styles.noOptions}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {noOptionsText == null\n ? t('select.noOptions')\n : typeof noOptionsText === 'function'\n ? noOptionsText(menu.searchQuery)\n : noOptionsText}\n </Typography>\n </div>\n ) : (\n renderRows(filteredOptions.map((opt, index) => ({ opt, index })))\n )}\n </List>\n </FloatingPanel>\n )\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type RefObject,\n} from 'react'\nimport type { ReactNode } from 'react'\nimport type { IconName } from '../../icons/names'\n\n/** A single selectable option — shared by `Select`, `MultiSelect` and `PhoneField`. */\nexport interface SelectOption {\n /** The value committed when this option is chosen. */\n value: string\n /** Display + search text. */\n label: string\n /** Greys out and blocks selecting this option. */\n disabled?: boolean\n /** Leading icon — a known `IconName` (rendered as `<Icon>`) or any node. */\n icon?: IconName | ReactNode\n /**\n * Extra search terms matched alongside the label (case-insensitive, substring) — e.g. a currency's\n * code (`'USD'`) or a country's calling code (`'995'`). Never shown.\n */\n keywords?: readonly string[]\n /** Content on the right of the row, before the selected tick (e.g. a code or a count). */\n trailing?: ReactNode\n /**\n * Group heading. Options sharing a `group` are listed together under it (groups in order of first\n * appearance, options keeping their order within a group); options without one stay ungrouped.\n */\n group?: string\n}\n\n/**\n * Stable-group the options: each group gathered at its first appearance, order kept within a group. A\n * list with no `group` at all is returned untouched (the common case costs nothing).\n */\nexport function groupOptions<T extends SelectOption>(options: readonly T[]): readonly T[] {\n if (!options.some((o) => o.group != null)) return options\n const buckets = new Map<string | undefined, T[]>()\n for (const o of options) {\n const bucket = buckets.get(o.group)\n if (bucket) bucket.push(o)\n else buckets.set(o.group, [o])\n }\n return [...buckets.values()].flat()\n}\n\nexport interface UseOptionMenuOptions {\n /** Base for the listbox / option ids (`${idBase}-listbox`, `${idBase}-opt-${i}`). */\n idBase: string\n options: readonly SelectOption[]\n /** Whether an option is selected (drives the initial highlight when `highlightSelected`). */\n isSelected: (option: SelectOption) => boolean\n /** Called when an option is picked (Enter / Space / click). */\n onPick: (option: SelectOption) => void\n /** Close the menu after a pick (single-select) or keep it open (multi-select). Defaults to `true`. */\n closeOnPick?: boolean\n /** On open, highlight the selected option (single-select) instead of the first. Defaults to `true`. */\n highlightSelected?: boolean\n /** Show a search box that filters by label + keywords. */\n searchable?: boolean\n /** The consumer filters `options` itself (server-side search) — skip the local filter. */\n onSearchChange?: (query: string) => void\n disabled?: boolean\n /** The element focus returns to when the menu closes with `refocus` (the trigger / the input). */\n focusRef: RefObject<HTMLElement | null>\n /** Runs on every close (e.g. mark a form field touched). */\n onClose?: () => void\n}\n\n/**\n * The state + keyboard model behind every option popover (internal): open / close, the search query\n * and its label + keywords filter, the highlighted row (skipping disabled ones), type-ahead when not\n * searchable, and one `handleKeyDown` for the trigger and the search box — Arrow / Home / End move,\n * Enter / Space pick, Escape closes (refocusing), Tab closes and moves on. Render it with `OptionMenu`.\n */\nexport function useOptionMenu({\n idBase,\n options,\n isSelected,\n onPick,\n closeOnPick = true,\n highlightSelected = true,\n searchable = false,\n onSearchChange,\n disabled = false,\n focusRef,\n onClose,\n}: UseOptionMenuOptions) {\n const listboxId = `${idBase}-listbox`\n const optionId = useCallback((index: number) => `${idBase}-opt-${index}`, [idBase])\n\n const [open, setOpen] = useState(false)\n const [searchQuery, setSearchQueryState] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const searchInputRef = useRef<HTMLInputElement | null>(null)\n // the floating panel forwards its node here, for the focus-leaves-the-widget check on blur\n const popoverRef = useRef<HTMLDivElement | null>(null)\n const typeahead = useRef({ buffer: '', timer: 0 })\n // latest callbacks without re-creating the stable handlers\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n // local filter by label + keywords (skipped when the consumer owns the options — server search), then\n // grouped, so the flat index the keyboard walks is exactly the rendered order\n const filteredOptions = useMemo(() => {\n const q = searchQuery.trim().toLowerCase()\n const matches =\n !searchable || onSearchChange || !q\n ? options\n : options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.keywords?.some((k) => k.toLowerCase().includes(q)),\n )\n return groupOptions(matches)\n }, [searchable, onSearchChange, searchQuery, options])\n\n const findEnabled = useCallback(\n (start: number, delta: number) => {\n let i = start\n while (i >= 0 && i < filteredOptions.length) {\n if (!filteredOptions[i].disabled) return i\n i += delta\n }\n return -1\n },\n [filteredOptions],\n )\n\n // single dismiss path: clears the search + type-ahead, notifies, optionally refocuses\n const closeMenu = useCallback(\n (refocus: boolean) => {\n setOpen(false)\n setSearchQueryState('')\n window.clearTimeout(typeahead.current.timer)\n typeahead.current.buffer = ''\n onCloseRef.current?.()\n if (refocus) focusRef.current?.focus()\n },\n [focusRef],\n )\n\n // on open: highlight the selected option (or the first enabled), focus the search box\n useEffect(() => {\n if (!open) return\n const selIdx = highlightSelected ? filteredOptions.findIndex(isSelected) : -1\n setHighlightedIndex(\n selIdx >= 0 && !filteredOptions[selIdx].disabled ? selIdx : findEnabled(0, 1),\n )\n if (searchable) requestAnimationFrame(() => searchInputRef.current?.focus())\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n // keep the highlighted option scrolled into view\n useEffect(() => {\n if (!open || highlightedIndex < 0) return\n document.getElementById(optionId(highlightedIndex))?.scrollIntoView?.({ block: 'nearest' })\n }, [open, highlightedIndex, optionId])\n\n // a new search → re-anchor the highlight to the first match\n useEffect(() => {\n if (open && searchable) setHighlightedIndex(findEnabled(0, 1))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [searchQuery])\n\n // the option count changed while open (async load / list shrink) → keep the highlight in range\n useEffect(() => {\n if (open) setHighlightedIndex((i) => (i < filteredOptions.length ? i : findEnabled(0, 1)))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filteredOptions.length])\n\n const openMenu = () => {\n if (!disabled) setOpen(true)\n }\n const toggleMenu = () => (open ? closeMenu(false) : openMenu())\n\n const setSearchQuery = (query: string) => {\n setSearchQueryState(query)\n onSearchChange?.(query)\n }\n\n const pick = (option: SelectOption | undefined) => {\n if (!option || option.disabled) return\n onPick(option)\n if (closeOnPick) closeMenu(true)\n }\n\n const moveHighlight = (delta: number) => {\n setHighlightedIndex((cur) => {\n const start = cur < 0 ? (delta > 0 ? 0 : filteredOptions.length - 1) : cur + delta\n const found = findEnabled(start, delta)\n return found === -1 ? cur : found\n })\n }\n\n // type-ahead (no search box): jump to the option whose label starts with the typed buffer\n const handleTypeahead = (char: string) => {\n const t = typeahead.current\n window.clearTimeout(t.timer)\n t.buffer += char.toLowerCase()\n t.timer = window.setTimeout(() => (t.buffer = ''), 500)\n const match = filteredOptions.findIndex(\n (o) => !o.disabled && o.label.toLowerCase().startsWith(t.buffer),\n )\n if (match >= 0) setHighlightedIndex(match)\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (disabled) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n open ? moveHighlight(1) : openMenu()\n break\n case 'ArrowUp':\n event.preventDefault()\n open ? moveHighlight(-1) : openMenu()\n break\n case 'Enter':\n event.preventDefault()\n if (!open) openMenu()\n else pick(filteredOptions[highlightedIndex])\n break\n case ' ':\n // Space opens a closed menu; picks only when open without a search box (so search can type spaces)\n if (!open) {\n event.preventDefault()\n openMenu()\n } else if (!searchable) {\n event.preventDefault()\n pick(filteredOptions[highlightedIndex])\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation() // don't let FloatingPanel's own Escape also fire closeMenu\n closeMenu(true)\n }\n break\n case 'Tab':\n // refocus the trigger so Tab continues from the field's visual spot, not the portaled search\n // input's DOM position (end of <body>); no preventDefault — let Tab move on\n if (open) closeMenu(true)\n break\n case 'Home':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(0, 1))\n }\n break\n case 'End':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(filteredOptions.length - 1, -1))\n }\n break\n default:\n if (\n !searchable &&\n open &&\n event.key.length === 1 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.altKey\n ) {\n handleTypeahead(event.key)\n }\n }\n }\n\n const activeId = open && highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined\n\n return {\n open,\n openMenu,\n closeMenu,\n toggleMenu,\n searchable,\n searchQuery,\n setSearchQuery,\n filteredOptions,\n highlightedIndex,\n setHighlightedIndex,\n isSelected,\n pick,\n handleKeyDown,\n listboxId,\n optionId,\n activeId,\n searchInputRef,\n popoverRef,\n }\n}\n\n/** Everything `useOptionMenu` returns — pass it to `<OptionMenu menu={…} />`. */\nexport type OptionMenuState = ReturnType<typeof useOptionMenu>\n"],"names":["OptionMenu","menu","anchorRef","size","searchPlaceholder","loading","loadingText","noOptionsText","showSelectedTick","multiselectable","labelledBy","ariaLabel","onSearchKeyDown","className","useT","searchPh","filteredOptions","highlightedIndex","renderOption","opt","index","selected","tick","jsx","ListItem","clsx","styles","jsxs","Icon","e","renderRows","rows","r","runs","row","last","run","i","headingId","Typography","FloatingPanel","List","Loader","groupOptions","options","o","buckets","bucket","useOptionMenu","idBase","isSelected","onPick","closeOnPick","highlightSelected","searchable","onSearchChange","disabled","focusRef","onClose","listboxId","optionId","useCallback","open","setOpen","useState","searchQuery","setSearchQueryState","setHighlightedIndex","searchInputRef","useRef","popoverRef","typeahead","onCloseRef","useMemo","q","matches","_a","k","findEnabled","start","delta","closeMenu","refocus","_b","useEffect","selIdx","openMenu","toggleMenu","setSearchQuery","query","pick","option","moveHighlight","cur","found","handleTypeahead","char","t","match","handleKeyDown","event","activeId"],"mappings":"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"}
1
+ {"version":3,"file":"useOptionMenu-Sp2d3Bzi.js","sources":["../src/components/OptionMenu/OptionMenu.tsx","../src/components/OptionMenu/useOptionMenu.ts"],"sourcesContent":["import type { KeyboardEvent, ReactNode, RefObject } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { FloatingPanel } from '../FloatingPanel/FloatingPanel'\nimport { Icon } from '../Icon'\nimport { List, ListItem, type ListItemSize } from '../List'\nimport { Loader } from '../Loader'\nimport { Typography } from '../Typography'\nimport type { OptionMenuState, SelectOption } from './useOptionMenu'\nimport styles from './OptionMenu.module.css'\n\nexport interface OptionMenuProps {\n /** The state from `useOptionMenu`. */\n menu: OptionMenuState\n /** What the panel anchors under (and matches the width of) — also excluded from outside-click. */\n anchorRef: RefObject<HTMLElement | null>\n /** Row size. */\n size: ListItemSize\n /** Search box placeholder + accessible label. Defaults to the localized \"Search…\". */\n searchPlaceholder?: string\n /** Show a loader row instead of the options (server-side search in flight). */\n loading?: boolean\n /** Text next to the loader. Defaults to the localized \"Loading…\". */\n loadingText?: ReactNode\n /** Empty-result content — a node or `(query) => node`. Defaults to the localized \"No Options\". */\n noOptionsText?: ReactNode | ((query: string) => ReactNode)\n /** Tick the selected option(s). Defaults to `true`. */\n showSelectedTick?: boolean\n /** `aria-multiselectable` on the listbox. */\n multiselectable?: boolean\n /** Labels the listbox (the field label id). */\n labelledBy?: string\n /** Accessible label for the listbox when there's no visible label. */\n ariaLabel?: string\n /** Wraps the search box's key handling (e.g. MultiSelect's Backspace-removes-a-chip). */\n onSearchKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void\n /** Extra class on the panel. */\n className?: string\n}\n\n/**\n * The option popover shared by `Select`, `MultiSelect` and `PhoneField` (internal): a `FloatingPanel`\n * anchored under the field, an optional sticky search box (`role=\"combobox\"`, `aria-activedescendant`),\n * and a scrolling `role=\"listbox\"` of `ListItem` options — icon, label, the option's `trailing`, a tick\n * when selected, the keyboard highlight, disabled rows inert, `group`ed options under a labelled heading —\n * plus the loading and empty rows. All state\n * and keys live in `useOptionMenu`; this only renders it.\n */\nexport function OptionMenu({\n menu,\n anchorRef,\n size,\n searchPlaceholder,\n loading = false,\n loadingText,\n noOptionsText,\n showSelectedTick = true,\n multiselectable = false,\n labelledBy,\n ariaLabel,\n onSearchKeyDown,\n className,\n}: OptionMenuProps) {\n const t = useT()\n const searchPh = searchPlaceholder ?? t('common.search')\n const { filteredOptions, highlightedIndex } = menu\n\n const renderOption = ({ opt, index }: { opt: SelectOption; index: number }) => {\n const selected = menu.isSelected(opt)\n const tick = selected && showSelectedTick\n return (\n <ListItem\n key={opt.value}\n id={menu.optionId(index)}\n role=\"option\"\n tabIndex={-1}\n aria-selected={selected}\n aria-current={undefined}\n clickable\n selected={selected}\n disabled={opt.disabled}\n icon={opt.icon}\n className={clsx(index === highlightedIndex && styles.active)}\n trailing={\n opt.trailing != null || tick ? (\n <span className={styles.trailing}>\n {opt.trailing}\n {tick && <Icon name=\"TickCircle\" size=\"sm\" />}\n </span>\n ) : undefined\n }\n onMouseEnter={() => !opt.disabled && menu.setHighlightedIndex(index)}\n // keep focus where it is (trigger / search box) — a multi-select stays open and typing keeps\n // working; a single-select refocuses its trigger on close anyway\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => menu.pick(opt)}\n >\n {opt.label}\n </ListItem>\n )\n }\n\n // consecutive runs of the same `group` (the hook already gathered them) → a labelled role=\"group\"\n // each; ungrouped runs render as plain rows\n const renderRows = (rows: { opt: SelectOption; index: number }[]) => {\n if (!rows.some((r) => r.opt.group != null)) return rows.map(renderOption)\n const runs: { group: string | undefined; rows: typeof rows }[] = []\n for (const row of rows) {\n const last = runs[runs.length - 1]\n if (last && last.group === row.opt.group) last.rows.push(row)\n else runs.push({ group: row.opt.group, rows: [row] })\n }\n return runs.map((run, i) => {\n if (run.group == null) return run.rows.map(renderOption)\n const headingId = `${menu.listboxId}-group-${i}`\n return (\n <div key={`group-${i}`} role=\"group\" aria-labelledby={headingId} className={styles.group}>\n <Typography\n as=\"div\"\n id={headingId}\n role=\"presentation\"\n variant=\"caption\"\n color=\"muted\"\n uppercase\n className={styles.groupLabel}\n >\n {run.group}\n </Typography>\n {run.rows.map(renderOption)}\n </div>\n )\n })\n }\n\n return (\n <FloatingPanel\n ref={menu.popoverRef}\n open={menu.open}\n triggerRef={anchorRef}\n onClose={menu.closeMenu}\n matchTriggerWidth\n className={clsx(styles.popover, className)}\n >\n {menu.searchable && (\n <div className={styles.search}>\n <Icon name=\"SearchNormal\" size=\"sm\" className={styles.searchIcon} aria-hidden=\"true\" />\n <input\n ref={menu.searchInputRef}\n className={styles.searchInput}\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={menu.listboxId}\n aria-activedescendant={menu.activeId}\n aria-autocomplete=\"list\"\n aria-label={searchPh}\n placeholder={searchPh}\n value={menu.searchQuery}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => menu.setSearchQuery(e.target.value)}\n onKeyDown={onSearchKeyDown ?? menu.handleKeyDown}\n />\n </div>\n )}\n\n {/* the listbox always carries its id (even when empty) so aria-controls never dangles */}\n <List\n role=\"listbox\"\n id={menu.listboxId}\n aria-labelledby={labelledBy}\n aria-label={labelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiselectable || undefined}\n size={size}\n className={styles.listbox}\n // clear the mouse highlight when the pointer leaves the list (no lingering hover)\n onMouseLeave={() => menu.setHighlightedIndex(-1)}\n >\n {loading ? (\n <div className={styles.loading}>\n <Loader size=\"sm\" />\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {loadingText ?? t('common.loading')}\n </Typography>\n </div>\n ) : filteredOptions.length === 0 ? (\n <div className={styles.noOptions}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {noOptionsText == null\n ? t('select.noOptions')\n : typeof noOptionsText === 'function'\n ? noOptionsText(menu.searchQuery)\n : noOptionsText}\n </Typography>\n </div>\n ) : (\n renderRows(filteredOptions.map((opt, index) => ({ opt, index })))\n )}\n </List>\n </FloatingPanel>\n )\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type RefObject,\n} from 'react'\nimport type { ReactNode } from 'react'\nimport type { IconName } from '../../icons/names'\n\n/** A single selectable option — shared by `Select`, `MultiSelect` and `PhoneField`. */\nexport interface SelectOption {\n /** The value committed when this option is chosen. */\n value: string\n /** Display + search text. */\n label: string\n /** Greys out and blocks selecting this option. */\n disabled?: boolean\n /** Leading icon — a known `IconName` (rendered as `<Icon>`) or any node. */\n icon?: IconName | ReactNode\n /**\n * Extra search terms matched alongside the label (case-insensitive, substring) — e.g. a currency's\n * code (`'USD'`) or a country's calling code (`'995'`). Never shown.\n */\n keywords?: readonly string[]\n /** Content on the right of the row, before the selected tick (e.g. a code or a count). */\n trailing?: ReactNode\n /**\n * Group heading. Options sharing a `group` are listed together under it (groups in order of first\n * appearance, options keeping their order within a group); options without one stay ungrouped.\n */\n group?: string\n}\n\n/**\n * Stable-group the options: each group gathered at its first appearance, order kept within a group. A\n * list with no `group` at all is returned untouched (the common case costs nothing).\n */\nexport function groupOptions<T extends SelectOption>(options: readonly T[]): readonly T[] {\n if (!options.some((o) => o.group != null)) return options\n const buckets = new Map<string | undefined, T[]>()\n for (const o of options) {\n const bucket = buckets.get(o.group)\n if (bucket) bucket.push(o)\n else buckets.set(o.group, [o])\n }\n return [...buckets.values()].flat()\n}\n\nexport interface UseOptionMenuOptions {\n /** Base for the listbox / option ids (`${idBase}-listbox`, `${idBase}-opt-${i}`). */\n idBase: string\n options: readonly SelectOption[]\n /** Whether an option is selected (drives the initial highlight when `highlightSelected`). */\n isSelected: (option: SelectOption) => boolean\n /** Called when an option is picked (Enter / Space / click). */\n onPick: (option: SelectOption) => void\n /** Close the menu after a pick (single-select) or keep it open (multi-select). Defaults to `true`. */\n closeOnPick?: boolean\n /** On open, highlight the selected option (single-select) instead of the first. Defaults to `true`. */\n highlightSelected?: boolean\n /** Show a search box that filters by label + keywords. */\n searchable?: boolean\n /** The consumer filters `options` itself (server-side search) — skip the local filter. */\n onSearchChange?: (query: string) => void\n disabled?: boolean\n /** The element focus returns to when the menu closes with `refocus` (the trigger / the input). */\n focusRef: RefObject<HTMLElement | null>\n /** Runs on every close (e.g. mark a form field touched). */\n onClose?: () => void\n}\n\n/**\n * The state + keyboard model behind every option popover (internal): open / close, the search query\n * and its label + keywords filter, the highlighted row (skipping disabled ones), type-ahead when not\n * searchable, and one `handleKeyDown` for the trigger and the search box — Arrow / Home / End move,\n * Enter / Space pick, Escape closes (refocusing), Tab closes and moves on. Render it with `OptionMenu`.\n */\nexport function useOptionMenu({\n idBase,\n options,\n isSelected,\n onPick,\n closeOnPick = true,\n highlightSelected = true,\n searchable = false,\n onSearchChange,\n disabled = false,\n focusRef,\n onClose,\n}: UseOptionMenuOptions) {\n const listboxId = `${idBase}-listbox`\n const optionId = useCallback((index: number) => `${idBase}-opt-${index}`, [idBase])\n\n const [open, setOpen] = useState(false)\n const [searchQuery, setSearchQueryState] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const searchInputRef = useRef<HTMLInputElement | null>(null)\n // the floating panel forwards its node here, for the focus-leaves-the-widget check on blur\n const popoverRef = useRef<HTMLDivElement | null>(null)\n const typeahead = useRef({ buffer: '', timer: 0 })\n // latest callbacks without re-creating the stable handlers\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n // local filter by label + keywords (skipped when the consumer owns the options — server search), then\n // grouped, so the flat index the keyboard walks is exactly the rendered order\n const filteredOptions = useMemo(() => {\n const q = searchQuery.trim().toLowerCase()\n const matches =\n !searchable || onSearchChange || !q\n ? options\n : options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.keywords?.some((k) => k.toLowerCase().includes(q)),\n )\n return groupOptions(matches)\n }, [searchable, onSearchChange, searchQuery, options])\n\n const findEnabled = useCallback(\n (start: number, delta: number) => {\n let i = start\n while (i >= 0 && i < filteredOptions.length) {\n if (!filteredOptions[i].disabled) return i\n i += delta\n }\n return -1\n },\n [filteredOptions],\n )\n\n // single dismiss path: clears the search + type-ahead, notifies, optionally refocuses\n const closeMenu = useCallback(\n (refocus: boolean) => {\n setOpen(false)\n setSearchQueryState('')\n window.clearTimeout(typeahead.current.timer)\n typeahead.current.buffer = ''\n onCloseRef.current?.()\n if (refocus) focusRef.current?.focus()\n },\n [focusRef],\n )\n\n // on open: highlight the selected option (or the first enabled), focus the search box\n useEffect(() => {\n if (!open) return\n const selIdx = highlightSelected ? filteredOptions.findIndex(isSelected) : -1\n setHighlightedIndex(\n selIdx >= 0 && !filteredOptions[selIdx].disabled ? selIdx : findEnabled(0, 1),\n )\n if (searchable) requestAnimationFrame(() => searchInputRef.current?.focus())\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n // keep the highlighted option scrolled into view\n useEffect(() => {\n if (!open || highlightedIndex < 0) return\n document.getElementById(optionId(highlightedIndex))?.scrollIntoView?.({ block: 'nearest' })\n }, [open, highlightedIndex, optionId])\n\n // a new search → re-anchor the highlight to the first match\n useEffect(() => {\n if (open && searchable) setHighlightedIndex(findEnabled(0, 1))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [searchQuery])\n\n // the option count changed while open (async load / list shrink) → keep the highlight in range\n useEffect(() => {\n if (open) setHighlightedIndex((i) => (i < filteredOptions.length ? i : findEnabled(0, 1)))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filteredOptions.length])\n\n const openMenu = () => {\n if (!disabled) setOpen(true)\n }\n const toggleMenu = () => (open ? closeMenu(false) : openMenu())\n\n const setSearchQuery = (query: string) => {\n setSearchQueryState(query)\n onSearchChange?.(query)\n }\n\n const pick = (option: SelectOption | undefined) => {\n if (!option || option.disabled) return\n onPick(option)\n if (closeOnPick) closeMenu(true)\n }\n\n const moveHighlight = (delta: number) => {\n setHighlightedIndex((cur) => {\n const start = cur < 0 ? (delta > 0 ? 0 : filteredOptions.length - 1) : cur + delta\n const found = findEnabled(start, delta)\n return found === -1 ? cur : found\n })\n }\n\n // type-ahead (no search box): jump to the option whose label starts with the typed buffer\n const handleTypeahead = (char: string) => {\n const t = typeahead.current\n window.clearTimeout(t.timer)\n t.buffer += char.toLowerCase()\n t.timer = window.setTimeout(() => (t.buffer = ''), 500)\n const match = filteredOptions.findIndex(\n (o) => !o.disabled && o.label.toLowerCase().startsWith(t.buffer),\n )\n if (match >= 0) setHighlightedIndex(match)\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (disabled) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n open ? moveHighlight(1) : openMenu()\n break\n case 'ArrowUp':\n event.preventDefault()\n open ? moveHighlight(-1) : openMenu()\n break\n case 'Enter':\n event.preventDefault()\n if (!open) openMenu()\n else pick(filteredOptions[highlightedIndex])\n break\n case ' ':\n // Space opens a closed menu; picks only when open without a search box (so search can type spaces)\n if (!open) {\n event.preventDefault()\n openMenu()\n } else if (!searchable) {\n event.preventDefault()\n pick(filteredOptions[highlightedIndex])\n }\n break\n case 'Escape':\n if (open) {\n event.preventDefault()\n event.stopPropagation() // don't let FloatingPanel's own Escape also fire closeMenu\n closeMenu(true)\n }\n break\n case 'Tab':\n // refocus the trigger so Tab continues from the field's visual spot, not the portaled search\n // input's DOM position (end of <body>); no preventDefault — let Tab move on\n if (open) closeMenu(true)\n break\n case 'Home':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(0, 1))\n }\n break\n case 'End':\n if (open) {\n event.preventDefault()\n setHighlightedIndex(findEnabled(filteredOptions.length - 1, -1))\n }\n break\n default:\n if (\n !searchable &&\n open &&\n event.key.length === 1 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.altKey\n ) {\n handleTypeahead(event.key)\n }\n }\n }\n\n const activeId = open && highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined\n\n return {\n open,\n openMenu,\n closeMenu,\n toggleMenu,\n searchable,\n searchQuery,\n setSearchQuery,\n filteredOptions,\n highlightedIndex,\n setHighlightedIndex,\n isSelected,\n pick,\n handleKeyDown,\n listboxId,\n optionId,\n activeId,\n searchInputRef,\n popoverRef,\n }\n}\n\n/** Everything `useOptionMenu` returns — pass it to `<OptionMenu menu={…} />`. */\nexport type OptionMenuState = ReturnType<typeof useOptionMenu>\n"],"names":["OptionMenu","menu","anchorRef","size","searchPlaceholder","loading","loadingText","noOptionsText","showSelectedTick","multiselectable","labelledBy","ariaLabel","onSearchKeyDown","className","useT","searchPh","filteredOptions","highlightedIndex","renderOption","opt","index","selected","tick","jsx","ListItem","clsx","styles","jsxs","Icon","e","renderRows","rows","r","runs","row","last","run","i","headingId","Typography","FloatingPanel","List","Loader","groupOptions","options","o","buckets","bucket","useOptionMenu","idBase","isSelected","onPick","closeOnPick","highlightSelected","searchable","onSearchChange","disabled","focusRef","onClose","listboxId","optionId","useCallback","open","setOpen","useState","searchQuery","setSearchQueryState","setHighlightedIndex","searchInputRef","useRef","popoverRef","typeahead","onCloseRef","useMemo","q","matches","_a","k","findEnabled","start","delta","closeMenu","refocus","_b","useEffect","selIdx","openMenu","toggleMenu","setSearchQuery","query","pick","option","moveHighlight","cur","found","handleTypeahead","char","t","match","handleKeyDown","event","activeId"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techzyapp/ui-library",
3
- "version": "1.0.48",
3
+ "version": "1.0.50",
4
4
  "description": "Techzy UI — reusable React component library for admin panels.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,108 +0,0 @@
1
- import { jsx as p, Fragment as K } from "react/jsx-runtime";
2
- import { useRouter as R, useRouterState as O, Navigate as S } from "@tanstack/react-router";
3
- import { useRef as l, useMemo as U, useEffect as _ } from "react";
4
- import { d as P, m as y } from "./ConfigProvider-DtyUlWk6.js";
5
- const W = 2048;
6
- let c = null, h = !1;
7
- const a = {
8
- queryKey: P,
9
- loginPath: "/login",
10
- isAuthPath: null
11
- };
12
- function w(t) {
13
- Object.assign(a, t);
14
- }
15
- const g = () => typeof window < "u", b = () => typeof window > "u" ? "http://localhost" : window.location.origin, q = (t, n) => {
16
- const u = n.length > 1 ? n.replace(/\/+$/, "") : n;
17
- return t === u || t.startsWith(`${u}/`);
18
- };
19
- function L(t, { loginPath: n, isAuthPath: u, origin: r = b() }) {
20
- if (typeof t != "string" || t.length === 0 || t.length > W || !t.startsWith("/") || t.startsWith("//") || t.startsWith("/\\")) return null;
21
- let e;
22
- try {
23
- e = new URL(t, r);
24
- } catch {
25
- return null;
26
- }
27
- if (e.origin !== r || e.pathname.startsWith("//") || q(e.pathname, n)) return null;
28
- try {
29
- if (u != null && u(e.pathname)) return null;
30
- } catch {
31
- }
32
- return `${e.pathname}${e.search}${e.hash}`;
33
- }
34
- const f = (t) => L(t, { loginPath: a.loginPath, isAuthPath: a.isAuthPath }), A = (t, n) => {
35
- try {
36
- return new URLSearchParams(t).get(n);
37
- } catch {
38
- return null;
39
- }
40
- }, E = (t, n) => f(A(t, n)) ?? (g() ? f(c) : null);
41
- function C(t, n = "/", u = a.queryKey) {
42
- return E(t, u) ?? n;
43
- }
44
- function D(t) {
45
- if (h || !g()) return null;
46
- const n = f(t);
47
- return !n || n === "/" ? null : (c = n, n);
48
- }
49
- function H() {
50
- c = null, h = g();
51
- }
52
- function I() {
53
- h = !1;
54
- }
55
- function T() {
56
- c = null, h = !1;
57
- }
58
- function M(t = "/") {
59
- return C(typeof window > "u" ? "" : window.location.search, t);
60
- }
61
- function N(t = "/") {
62
- const n = y();
63
- w({ queryKey: n });
64
- const u = R(), r = l(null);
65
- r.current === null && (r.current = u.state.location.pathname);
66
- const e = l(null), d = O({
67
- select: (s) => (s.location.pathname === r.current && (e.current = A(s.location.searchStr, n)), e.current)
68
- }), o = l(null), i = f(d);
69
- return i ? o.current = i : o.current === null && (o.current = E("", n)), o.current ?? t;
70
- }
71
- function Q() {
72
- c = null;
73
- }
74
- const Y = ({ isAuthenticated: t, redirectTo: n = "/login", children: u }) => {
75
- const r = typeof t == "function" ? t() : t, e = y(), d = R();
76
- w({ queryKey: e, loginPath: n });
77
- const o = l(void 0);
78
- if (r) o.current = void 0;
79
- else if (o.current === void 0) {
80
- const { pathname: s, searchStr: $, hash: m } = d.state.location;
81
- o.current = D(`${s}${$}${m ? `#${m}` : ""}`);
82
- }
83
- const i = U(
84
- () => r ? null : /* @__PURE__ */ p(
85
- S,
86
- {
87
- to: n,
88
- search: o.current ? { [e]: o.current } : {},
89
- replace: !0
90
- }
91
- ),
92
- [r, n, e]
93
- );
94
- return _(() => {
95
- r && T();
96
- }, [r]), r ? /* @__PURE__ */ p(K, { children: u }) : i;
97
- };
98
- export {
99
- Y as A,
100
- w as a,
101
- H as b,
102
- Q as c,
103
- I as e,
104
- M as g,
105
- C as r,
106
- N as u
107
- };
108
- //# sourceMappingURL=AuthGuard-BTSRwF04.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthGuard-BTSRwF04.js","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab. Memory only — a\n// path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/** The target for a search string — its param, else the remembered one — or `null` when there's none. */\nconst findAuthRedirect = (searchStr: string, queryKey: string) =>\n safe(paramOf(searchStr, queryKey)) ?? (isBrowser() ? safe(remembered) : null)\n\n/** @internal The target for a search string: its param, else the remembered one, else `fallback`. */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). The param name follows `config.keys.redirectQueryKey` once the guard, the\n * shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n return resolveAuthRedirect(typeof window === 'undefined' ? '' : window.location.search, fallback)\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). It doesn't clear anything; the target is forgotten once `AuthGuard` renders signed-in\n * content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) found.current = fromParam\n else if (found.current === null) found.current = findAuthRedirect('', queryKey)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport { authRedirectConsumed, configureAuthRedirect, rememberAuthRedirect } from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s). Once it renders signed-in content, the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","findAuthRedirect","queryKey","resolveAuthRedirect","fallback","rememberAuthRedirect","target","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","found","fromParam","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const R=require("react/jsx-runtime"),a=require("@tanstack/react-router"),i=require("react"),y=require("./ConfigProvider-CYSpuSMJ.cjs"),O=2048;let o=null,d=!1;const f={queryKey:y.DEFAULT_REDIRECT_QUERY_KEY,loginPath:"/login",isAuthPath:null};function m(t){Object.assign(f,t)}const p=()=>typeof window<"u",S=()=>typeof window>"u"?"http://localhost":window.location.origin,K=(t,e)=>{const u=e.length>1?e.replace(/\/+$/,""):e;return t===u||t.startsWith(`${u}/`)};function P(t,{loginPath:e,isAuthPath:u,origin:r=S()}){if(typeof t!="string"||t.length===0||t.length>O||!t.startsWith("/")||t.startsWith("//")||t.startsWith("/\\"))return null;let n;try{n=new URL(t,r)}catch{return null}if(n.origin!==r||n.pathname.startsWith("//")||K(n.pathname,e))return null;try{if(u!=null&&u(n.pathname))return null}catch{}return`${n.pathname}${n.search}${n.hash}`}const h=t=>P(t,{loginPath:f.loginPath,isAuthPath:f.isAuthPath}),w=(t,e)=>{try{return new URLSearchParams(t).get(e)}catch{return null}},E=(t,e)=>h(w(t,e))??(p()?h(o):null);function $(t,e="/",u=f.queryKey){return E(t,u)??e}function U(t){if(d||!p())return null;const e=h(t);return!e||e==="/"?null:(o=e,e)}function _(){o=null,d=p()}function W(){d=!1}function b(){o=null,d=!1}function j(t="/"){return $(typeof window>"u"?"":window.location.search,t)}function C(t="/"){const e=y.useRedirectQueryKey();m({queryKey:e});const u=a.useRouter(),r=i.useRef(null);r.current===null&&(r.current=u.state.location.pathname);const n=i.useRef(null),g=a.useRouterState({select:l=>(l.location.pathname===r.current&&(n.current=w(l.location.searchStr,e)),n.current)}),c=i.useRef(null),s=h(g);return s?c.current=s:c.current===null&&(c.current=E("",e)),c.current??t}function L(){o=null}const x=({isAuthenticated:t,redirectTo:e="/login",children:u})=>{const r=typeof t=="function"?t():t,n=y.useRedirectQueryKey(),g=a.useRouter();m({queryKey:n,loginPath:e});const c=i.useRef(void 0);if(r)c.current=void 0;else if(c.current===void 0){const{pathname:l,searchStr:q,hash:A}=g.state.location;c.current=U(`${l}${q}${A?`#${A}`:""}`)}const s=i.useMemo(()=>r?null:R.jsx(a.Navigate,{to:e,search:c.current?{[n]:c.current}:{},replace:!0}),[r,e,n]);return i.useEffect(()=>{r&&b()},[r]),r?R.jsx(R.Fragment,{children:u}):s};exports.AuthGuard=x;exports.beginSignOut=_;exports.clearAuthRedirect=L;exports.configureAuthRedirect=m;exports.endSignOut=W;exports.getAuthRedirect=j;exports.resolveAuthRedirect=$;exports.useAuthRedirect=C;
2
- //# sourceMappingURL=AuthGuard-CLqroYbX.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthGuard-CLqroYbX.cjs","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab. Memory only — a\n// path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/** The target for a search string — its param, else the remembered one — or `null` when there's none. */\nconst findAuthRedirect = (searchStr: string, queryKey: string) =>\n safe(paramOf(searchStr, queryKey)) ?? (isBrowser() ? safe(remembered) : null)\n\n/** @internal The target for a search string: its param, else the remembered one, else `fallback`. */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). The param name follows `config.keys.redirectQueryKey` once the guard, the\n * shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n return resolveAuthRedirect(typeof window === 'undefined' ? '' : window.location.search, fallback)\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). It doesn't clear anything; the target is forgotten once `AuthGuard` renders signed-in\n * content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) found.current = fromParam\n else if (found.current === null) found.current = findAuthRedirect('', queryKey)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport { authRedirectConsumed, configureAuthRedirect, rememberAuthRedirect } from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s). Once it renders signed-in content, the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","findAuthRedirect","queryKey","resolveAuthRedirect","fallback","rememberAuthRedirect","target","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","s","found","fromParam","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"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"}