@techzyapp/ui-library 1.0.28 → 1.0.30

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 (363) hide show
  1. package/dist/{AdminRoot-BTvmassR.js → AdminRoot-9HGp3Mds.js} +5 -5
  2. package/dist/{AdminRoot-BTvmassR.js.map → AdminRoot-9HGp3Mds.js.map} +1 -1
  3. package/dist/{AdminRoot-DM-cZCpN.cjs → AdminRoot-D24UJ-4a.cjs} +2 -2
  4. package/dist/{AdminRoot-DM-cZCpN.cjs.map → AdminRoot-D24UJ-4a.cjs.map} +1 -1
  5. package/dist/{Alert-v-lelDih.js → Alert-CJono1TJ.js} +3 -3
  6. package/dist/{Alert-v-lelDih.js.map → Alert-CJono1TJ.js.map} +1 -1
  7. package/dist/{Alert-CFm6MU0u.cjs → Alert-VFQuuII6.cjs} +2 -2
  8. package/dist/{Alert-CFm6MU0u.cjs.map → Alert-VFQuuII6.cjs.map} +1 -1
  9. package/dist/{Breadcrumbs-3wHPNa0P.cjs → Breadcrumbs-DCEHxpSi.cjs} +2 -2
  10. package/dist/{Breadcrumbs-3wHPNa0P.cjs.map → Breadcrumbs-DCEHxpSi.cjs.map} +1 -1
  11. package/dist/{Breadcrumbs-Cgd-u3aK.js → Breadcrumbs-XWU8tRvs.js} +3 -3
  12. package/dist/{Breadcrumbs-Cgd-u3aK.js.map → Breadcrumbs-XWU8tRvs.js.map} +1 -1
  13. package/dist/{Button-BLW9yV8W.js → Button-CWMNNiia.js} +2 -2
  14. package/dist/{Button-BLW9yV8W.js.map → Button-CWMNNiia.js.map} +1 -1
  15. package/dist/{Button-KRGjJdMV.cjs → Button-CusxDmfq.cjs} +2 -2
  16. package/dist/{Button-KRGjJdMV.cjs.map → Button-CusxDmfq.cjs.map} +1 -1
  17. package/dist/{Calendar-CoTCOOUu.cjs → Calendar-BEQbZixA.cjs} +2 -2
  18. package/dist/{Calendar-CoTCOOUu.cjs.map → Calendar-BEQbZixA.cjs.map} +1 -1
  19. package/dist/{Calendar-sLA-xa0B.js → Calendar-Db3rr1VD.js} +3 -3
  20. package/dist/{Calendar-sLA-xa0B.js.map → Calendar-Db3rr1VD.js.map} +1 -1
  21. package/dist/{Card-zTkvreQu.cjs → Card-CUUh4mlB.cjs} +2 -2
  22. package/dist/{Card-zTkvreQu.cjs.map → Card-CUUh4mlB.cjs.map} +1 -1
  23. package/dist/{Card-6fiSEC0z.js → Card-MxYfQTOY.js} +2 -2
  24. package/dist/{Card-6fiSEC0z.js.map → Card-MxYfQTOY.js.map} +1 -1
  25. package/dist/{Chip-CqOqfafx.cjs → Chip-D12KcV4_.cjs} +2 -2
  26. package/dist/{Chip-CqOqfafx.cjs.map → Chip-D12KcV4_.cjs.map} +1 -1
  27. package/dist/{Chip-C-5Z5wsC.js → Chip-Zh1OB9nV.js} +2 -2
  28. package/dist/{Chip-C-5Z5wsC.js.map → Chip-Zh1OB9nV.js.map} +1 -1
  29. package/dist/{CodeBlock-rPaqO7yD.js → CodeBlock-CkrTnpcj.js} +3 -3
  30. package/dist/{CodeBlock-rPaqO7yD.js.map → CodeBlock-CkrTnpcj.js.map} +1 -1
  31. package/dist/{CodeBlock-DFiHDZXh.cjs → CodeBlock-DAM7BkHK.cjs} +2 -2
  32. package/dist/{CodeBlock-DFiHDZXh.cjs.map → CodeBlock-DAM7BkHK.cjs.map} +1 -1
  33. package/dist/{ColorPicker-Bqypsy5E.cjs → ColorPicker-BcCozxIe.cjs} +2 -2
  34. package/dist/{ColorPicker-Bqypsy5E.cjs.map → ColorPicker-BcCozxIe.cjs.map} +1 -1
  35. package/dist/{ColorPicker-DXDAXvlA.js → ColorPicker-DqxVgUoD.js} +3 -3
  36. package/dist/{ColorPicker-DXDAXvlA.js.map → ColorPicker-DqxVgUoD.js.map} +1 -1
  37. package/dist/{ColorPickerPanel-C9ARc_uD.cjs → ColorPickerPanel-DAOESLCe.cjs} +2 -2
  38. package/dist/{ColorPickerPanel-C9ARc_uD.cjs.map → ColorPickerPanel-DAOESLCe.cjs.map} +1 -1
  39. package/dist/{ColorPickerPanel-6lQC1URc.js → ColorPickerPanel-DZjN8NNn.js} +2 -2
  40. package/dist/{ColorPickerPanel-6lQC1URc.js.map → ColorPickerPanel-DZjN8NNn.js.map} +1 -1
  41. package/dist/{ColorRamp-DQ8wkgvF.js → ColorRamp-DS5LVpRF.js} +2 -2
  42. package/dist/{ColorRamp-DQ8wkgvF.js.map → ColorRamp-DS5LVpRF.js.map} +1 -1
  43. package/dist/{ColorRamp-B9OWxCOK.cjs → ColorRamp-_KwlPQ-T.cjs} +2 -2
  44. package/dist/{ColorRamp-B9OWxCOK.cjs.map → ColorRamp-_KwlPQ-T.cjs.map} +1 -1
  45. package/dist/{ConfigProvider-B_RSn9bb.js → ConfigProvider-BbsI15b-.js} +2 -2
  46. package/dist/{ConfigProvider-B_RSn9bb.js.map → ConfigProvider-BbsI15b-.js.map} +1 -1
  47. package/dist/{ConfigProvider-BElY0HuV.cjs → ConfigProvider-ByLHqXpv.cjs} +2 -2
  48. package/dist/{ConfigProvider-BElY0HuV.cjs.map → ConfigProvider-ByLHqXpv.cjs.map} +1 -1
  49. package/dist/{CopyButton-BplPYm8i.js → CopyButton-D4s8aeSE.js} +3 -3
  50. package/dist/{CopyButton-BplPYm8i.js.map → CopyButton-D4s8aeSE.js.map} +1 -1
  51. package/dist/{CopyButton-B5aicGl3.cjs → CopyButton-SFwjKod9.cjs} +2 -2
  52. package/dist/{CopyButton-B5aicGl3.cjs.map → CopyButton-SFwjKod9.cjs.map} +1 -1
  53. package/dist/{DatePicker-U5TJ9FYM.js → DatePicker-DGwjCHfd.js} +4 -4
  54. package/dist/{DatePicker-U5TJ9FYM.js.map → DatePicker-DGwjCHfd.js.map} +1 -1
  55. package/dist/{DatePicker-Cdl2JYBd.cjs → DatePicker-ENbn2Vab.cjs} +2 -2
  56. package/dist/{DatePicker-Cdl2JYBd.cjs.map → DatePicker-ENbn2Vab.cjs.map} +1 -1
  57. package/dist/{DateTimePicker-DUFtddxJ.cjs → DateTimePicker-BQUmsFwX.cjs} +2 -2
  58. package/dist/{DateTimePicker-DUFtddxJ.cjs.map → DateTimePicker-BQUmsFwX.cjs.map} +1 -1
  59. package/dist/{DateTimePicker-laJsZYJX.js → DateTimePicker-CwVkQiun.js} +7 -7
  60. package/dist/{DateTimePicker-laJsZYJX.js.map → DateTimePicker-CwVkQiun.js.map} +1 -1
  61. package/dist/{DescriptionList-Y9jF_4L0.js → DescriptionList-0qjKr6GN.js} +4 -4
  62. package/dist/{DescriptionList-Y9jF_4L0.js.map → DescriptionList-0qjKr6GN.js.map} +1 -1
  63. package/dist/{DescriptionList-BCvOX8fg.cjs → DescriptionList-U5z2Faf4.cjs} +2 -2
  64. package/dist/{DescriptionList-BCvOX8fg.cjs.map → DescriptionList-U5z2Faf4.cjs.map} +1 -1
  65. package/dist/{EmptyState-CO_NRZ6w.cjs → EmptyState-B2_4BN4l.cjs} +2 -2
  66. package/dist/{EmptyState-CO_NRZ6w.cjs.map → EmptyState-B2_4BN4l.cjs.map} +1 -1
  67. package/dist/{EmptyState-BtwuzX9Z.js → EmptyState-DwT9_HW7.js} +2 -2
  68. package/dist/{EmptyState-BtwuzX9Z.js.map → EmptyState-DwT9_HW7.js.map} +1 -1
  69. package/dist/ErrorBoundary-CYSOAQlB.cjs +2 -0
  70. package/dist/ErrorBoundary-CYSOAQlB.cjs.map +1 -0
  71. package/dist/ErrorBoundary-CsDHKYB4.js +163 -0
  72. package/dist/ErrorBoundary-CsDHKYB4.js.map +1 -0
  73. package/dist/{FileCard-C3a2yDhK.js → FileCard-B9f9RoXS.js} +3 -3
  74. package/dist/{FileCard-C3a2yDhK.js.map → FileCard-B9f9RoXS.js.map} +1 -1
  75. package/dist/{FileCard-DKjDQRzZ.cjs → FileCard-zuUYik-F.cjs} +2 -2
  76. package/dist/{FileCard-DKjDQRzZ.cjs.map → FileCard-zuUYik-F.cjs.map} +1 -1
  77. package/dist/{FileUploader-CuOHWkiG.js → FileUploader-Dh2zA50t.js} +5 -5
  78. package/dist/{FileUploader-CuOHWkiG.js.map → FileUploader-Dh2zA50t.js.map} +1 -1
  79. package/dist/{FileUploader-VIOg03pl.cjs → FileUploader-Y8hiyIpp.cjs} +2 -2
  80. package/dist/{FileUploader-VIOg03pl.cjs.map → FileUploader-Y8hiyIpp.cjs.map} +1 -1
  81. package/dist/{Flag-aOQncoEZ.cjs → Flag-BpTQAgbD.cjs} +2 -2
  82. package/dist/{Flag-aOQncoEZ.cjs.map → Flag-BpTQAgbD.cjs.map} +1 -1
  83. package/dist/{Flag-kpUfmrwC.js → Flag-CmDXvd7j.js} +2 -2
  84. package/dist/{Flag-kpUfmrwC.js.map → Flag-CmDXvd7j.js.map} +1 -1
  85. package/dist/{FullscreenToggle-CMifmPD3.js → FullscreenToggle-2IYIS5KF.js} +3 -3
  86. package/dist/{FullscreenToggle-CMifmPD3.js.map → FullscreenToggle-2IYIS5KF.js.map} +1 -1
  87. package/dist/{FullscreenToggle-BSwxQEaG.cjs → FullscreenToggle-CeGgw3z1.cjs} +2 -2
  88. package/dist/{FullscreenToggle-BSwxQEaG.cjs.map → FullscreenToggle-CeGgw3z1.cjs.map} +1 -1
  89. package/dist/{IconButton-A2B0bqC-.cjs → IconButton-BNa0yLcv.cjs} +2 -2
  90. package/dist/{IconButton-A2B0bqC-.cjs.map → IconButton-BNa0yLcv.cjs.map} +1 -1
  91. package/dist/{IconButton-Dq17Fekm.js → IconButton-GU3Ud4Zg.js} +2 -2
  92. package/dist/{IconButton-Dq17Fekm.js.map → IconButton-GU3Ud4Zg.js.map} +1 -1
  93. package/dist/{Loader-CwyoKoWY.js → Loader-C1uaCtx6.js} +2 -2
  94. package/dist/{Loader-CwyoKoWY.js.map → Loader-C1uaCtx6.js.map} +1 -1
  95. package/dist/{Loader-D9nteBXt.cjs → Loader-Cpr9-OOZ.cjs} +2 -2
  96. package/dist/{Loader-D9nteBXt.cjs.map → Loader-Cpr9-OOZ.cjs.map} +1 -1
  97. package/dist/{Modal-CQDcYS-Y.cjs → Modal-DFeBHv-Q.cjs} +2 -2
  98. package/dist/{Modal-CQDcYS-Y.cjs.map → Modal-DFeBHv-Q.cjs.map} +1 -1
  99. package/dist/{Modal-cz6JIsZn.js → Modal-DHP2R3K3.js} +3 -3
  100. package/dist/{Modal-cz6JIsZn.js.map → Modal-DHP2R3K3.js.map} +1 -1
  101. package/dist/{MultiSelect-C6l0LpIs.js → MultiSelect-B-FPQ08c.js} +4 -4
  102. package/dist/{MultiSelect-C6l0LpIs.js.map → MultiSelect-B-FPQ08c.js.map} +1 -1
  103. package/dist/{MultiSelect-BIwE6wb7.cjs → MultiSelect-S5VG9g3l.cjs} +2 -2
  104. package/dist/{MultiSelect-BIwE6wb7.cjs.map → MultiSelect-S5VG9g3l.cjs.map} +1 -1
  105. package/dist/{NumberField-BpUTV_Qn.js → NumberField-CzyvDMRV.js} +3 -3
  106. package/dist/{NumberField-BpUTV_Qn.js.map → NumberField-CzyvDMRV.js.map} +1 -1
  107. package/dist/{NumberField-IyhO4OpJ.cjs → NumberField-SSGXlF8U.cjs} +2 -2
  108. package/dist/{NumberField-IyhO4OpJ.cjs.map → NumberField-SSGXlF8U.cjs.map} +1 -1
  109. package/dist/{OtpField-BoLxbGtY.js → OtpField-CMoJqcx1.js} +2 -2
  110. package/dist/{OtpField-BoLxbGtY.js.map → OtpField-CMoJqcx1.js.map} +1 -1
  111. package/dist/{OtpField-HMrxkdiy.cjs → OtpField-Pr7Ch0El.cjs} +2 -2
  112. package/dist/{OtpField-HMrxkdiy.cjs.map → OtpField-Pr7Ch0El.cjs.map} +1 -1
  113. package/dist/{PageLayout-DtWG-6dn.cjs → PageLayout-BIMkjq-q.cjs} +2 -2
  114. package/dist/{PageLayout-DtWG-6dn.cjs.map → PageLayout-BIMkjq-q.cjs.map} +1 -1
  115. package/dist/{PageLayout-G8F1WgC-.js → PageLayout-Ctr-IEzX.js} +2 -2
  116. package/dist/{PageLayout-G8F1WgC-.js.map → PageLayout-Ctr-IEzX.js.map} +1 -1
  117. package/dist/{PageNotFound-DG8xXPL3.cjs → PageNotFound-CnhBheI4.cjs} +2 -2
  118. package/dist/{PageNotFound-DG8xXPL3.cjs.map → PageNotFound-CnhBheI4.cjs.map} +1 -1
  119. package/dist/{PageNotFound-CeKIMZ55.js → PageNotFound-KKJTeaRF.js} +5 -5
  120. package/dist/{PageNotFound-CeKIMZ55.js.map → PageNotFound-KKJTeaRF.js.map} +1 -1
  121. package/dist/{Pagination-Br8P3KwE.cjs → Pagination-BD5WOW98.cjs} +2 -2
  122. package/dist/{Pagination-Br8P3KwE.cjs.map → Pagination-BD5WOW98.cjs.map} +1 -1
  123. package/dist/{Pagination-CE1uKrR4.js → Pagination-Oyms2ERd.js} +2 -2
  124. package/dist/{Pagination-CE1uKrR4.js.map → Pagination-Oyms2ERd.js.map} +1 -1
  125. package/dist/{PaletteField-BBPbkDcp.js → PaletteField-BHzzzdou.js} +3 -3
  126. package/dist/{PaletteField-BBPbkDcp.js.map → PaletteField-BHzzzdou.js.map} +1 -1
  127. package/dist/{PaletteField-DwvSn6V6.cjs → PaletteField-CCQGW5LC.cjs} +2 -2
  128. package/dist/{PaletteField-DwvSn6V6.cjs.map → PaletteField-CCQGW5LC.cjs.map} +1 -1
  129. package/dist/{PhoneField-BclMbl7L.cjs → PhoneField-5zGY4Wko.cjs} +2 -2
  130. package/dist/{PhoneField-BclMbl7L.cjs.map → PhoneField-5zGY4Wko.cjs.map} +1 -1
  131. package/dist/{PhoneField-B-L0xAtD.js → PhoneField-CBfmChPx.js} +4 -4
  132. package/dist/{PhoneField-B-L0xAtD.js.map → PhoneField-CBfmChPx.js.map} +1 -1
  133. package/dist/{Popconfirm-BgpvCBy1.js → Popconfirm-BtGDhqrc.js} +3 -3
  134. package/dist/{Popconfirm-BgpvCBy1.js.map → Popconfirm-BtGDhqrc.js.map} +1 -1
  135. package/dist/{Popconfirm-DD8F8SXn.cjs → Popconfirm-CkBdntxV.cjs} +2 -2
  136. package/dist/{Popconfirm-DD8F8SXn.cjs.map → Popconfirm-CkBdntxV.cjs.map} +1 -1
  137. package/dist/{Progress-_aZ8XOJr.cjs → Progress-Bwxx71Ns.cjs} +2 -2
  138. package/dist/{Progress-_aZ8XOJr.cjs.map → Progress-Bwxx71Ns.cjs.map} +1 -1
  139. package/dist/{Progress-L5koRRJp.js → Progress-pTbaOSDd.js} +2 -2
  140. package/dist/{Progress-L5koRRJp.js.map → Progress-pTbaOSDd.js.map} +1 -1
  141. package/dist/{QueryError-tBuIQRgv.js → QueryError-Bu_MNGek.js} +2 -2
  142. package/dist/{QueryError-tBuIQRgv.js.map → QueryError-Bu_MNGek.js.map} +1 -1
  143. package/dist/{QueryError-BMH8X69O.cjs → QueryError-C01oichG.cjs} +2 -2
  144. package/dist/{QueryError-BMH8X69O.cjs.map → QueryError-C01oichG.cjs.map} +1 -1
  145. package/dist/{RemoveDialog-DBKYnTYU.cjs → RemoveDialog-Bm2mJB3l.cjs} +2 -2
  146. package/dist/{RemoveDialog-DBKYnTYU.cjs.map → RemoveDialog-Bm2mJB3l.cjs.map} +1 -1
  147. package/dist/{RemoveDialog-C9_UzFBf.js → RemoveDialog-C2uJzWi-.js} +5 -5
  148. package/dist/{RemoveDialog-C9_UzFBf.js.map → RemoveDialog-C2uJzWi-.js.map} +1 -1
  149. package/dist/RichTextEditor-BFeJn2lr.js +916 -0
  150. package/dist/RichTextEditor-BFeJn2lr.js.map +1 -0
  151. package/dist/RichTextEditor-hOfxJEPX.cjs +2 -0
  152. package/dist/RichTextEditor-hOfxJEPX.cjs.map +1 -0
  153. package/dist/{RootLayout-p8ArA6wA.js → RootLayout-CxncyjCz.js} +13 -13
  154. package/dist/{RootLayout-p8ArA6wA.js.map → RootLayout-CxncyjCz.js.map} +1 -1
  155. package/dist/{RootLayout-DG2dXhXn.cjs → RootLayout-XEcU_MBs.cjs} +2 -2
  156. package/dist/{RootLayout-DG2dXhXn.cjs.map → RootLayout-XEcU_MBs.cjs.map} +1 -1
  157. package/dist/{Select-BuVfUiw-.cjs → Select-CVVJKAtS.cjs} +2 -2
  158. package/dist/{Select-BuVfUiw-.cjs.map → Select-CVVJKAtS.cjs.map} +1 -1
  159. package/dist/{Select-BAR_aVSz.js → Select-d9LDI8O3.js} +3 -3
  160. package/dist/{Select-BAR_aVSz.js.map → Select-d9LDI8O3.js.map} +1 -1
  161. package/dist/{Sidebar-NI5HGGYF.cjs → Sidebar-B8ecHwZr.cjs} +2 -2
  162. package/dist/{Sidebar-NI5HGGYF.cjs.map → Sidebar-B8ecHwZr.cjs.map} +1 -1
  163. package/dist/{Sidebar-CsWcjSTx.js → Sidebar-BgCfnZBF.js} +3 -3
  164. package/dist/{Sidebar-CsWcjSTx.js.map → Sidebar-BgCfnZBF.js.map} +1 -1
  165. package/dist/{SpeedDial-DF-ILheU.js → SpeedDial-CBVwgnFp.js} +2 -2
  166. package/dist/{SpeedDial-DF-ILheU.js.map → SpeedDial-CBVwgnFp.js.map} +1 -1
  167. package/dist/{SpeedDial-C_rZkHmF.cjs → SpeedDial-CEr2JWQb.cjs} +2 -2
  168. package/dist/{SpeedDial-C_rZkHmF.cjs.map → SpeedDial-CEr2JWQb.cjs.map} +1 -1
  169. package/dist/{Stepper-CT7n113R.cjs → Stepper-DOSc03YV.cjs} +2 -2
  170. package/dist/{Stepper-CT7n113R.cjs.map → Stepper-DOSc03YV.cjs.map} +1 -1
  171. package/dist/{Stepper-B39Ax_w6.js → Stepper-DtYamv1q.js} +2 -2
  172. package/dist/{Stepper-B39Ax_w6.js.map → Stepper-DtYamv1q.js.map} +1 -1
  173. package/dist/{Table-CH_oiEP3.js → Table-AzNzUAkl.js} +15 -15
  174. package/dist/{Table-CH_oiEP3.js.map → Table-AzNzUAkl.js.map} +1 -1
  175. package/dist/{Table-DD_uysnY.cjs → Table-CrpWhZUg.cjs} +2 -2
  176. package/dist/{Table-DD_uysnY.cjs.map → Table-CrpWhZUg.cjs.map} +1 -1
  177. package/dist/{Tabs-C1N9FgAq.cjs → Tabs-CMnLXRjA.cjs} +2 -2
  178. package/dist/{Tabs-C1N9FgAq.cjs.map → Tabs-CMnLXRjA.cjs.map} +1 -1
  179. package/dist/{Tabs-By86Cmpw.js → Tabs-D1RGhKsa.js} +2 -2
  180. package/dist/{Tabs-By86Cmpw.js.map → Tabs-D1RGhKsa.js.map} +1 -1
  181. package/dist/{TagsField-RX-x45-j.cjs → TagsField-DcuSn7wL.cjs} +2 -2
  182. package/dist/{TagsField-RX-x45-j.cjs.map → TagsField-DcuSn7wL.cjs.map} +1 -1
  183. package/dist/{TagsField-BiOyAadf.js → TagsField-DuQEFHZ3.js} +4 -4
  184. package/dist/{TagsField-BiOyAadf.js.map → TagsField-DuQEFHZ3.js.map} +1 -1
  185. package/dist/{TextField-CdbanZuk.cjs → TextField-E85pvJQC.cjs} +2 -2
  186. package/dist/{TextField-CdbanZuk.cjs.map → TextField-E85pvJQC.cjs.map} +1 -1
  187. package/dist/{TextField-CkronCRC.js → TextField-SGYWviFf.js} +3 -3
  188. package/dist/{TextField-CkronCRC.js.map → TextField-SGYWviFf.js.map} +1 -1
  189. package/dist/{ThemeToggle-C4QhDd76.cjs → ThemeToggle-BdlxzYNt.cjs} +2 -2
  190. package/dist/{ThemeToggle-C4QhDd76.cjs.map → ThemeToggle-BdlxzYNt.cjs.map} +1 -1
  191. package/dist/{ThemeToggle-BYUEH6be.js → ThemeToggle-C2kjFrD_.js} +3 -3
  192. package/dist/{ThemeToggle-BYUEH6be.js.map → ThemeToggle-C2kjFrD_.js.map} +1 -1
  193. package/dist/{TimeColumns-yzjScNU8.js → TimeColumns-BS1d0qOp.js} +2 -2
  194. package/dist/{TimeColumns-yzjScNU8.js.map → TimeColumns-BS1d0qOp.js.map} +1 -1
  195. package/dist/{TimeColumns-Cl0_IRf0.cjs → TimeColumns-D7-O4Qyt.cjs} +2 -2
  196. package/dist/{TimeColumns-Cl0_IRf0.cjs.map → TimeColumns-D7-O4Qyt.cjs.map} +1 -1
  197. package/dist/{TimePicker-CoIdMv1S.js → TimePicker-DlzYNDN1.js} +5 -5
  198. package/dist/{TimePicker-CoIdMv1S.js.map → TimePicker-DlzYNDN1.js.map} +1 -1
  199. package/dist/{TimePicker-CJGVGETl.cjs → TimePicker-Dzb3gycP.cjs} +2 -2
  200. package/dist/{TimePicker-CJGVGETl.cjs.map → TimePicker-Dzb3gycP.cjs.map} +1 -1
  201. package/dist/{Toaster-lv5cJhib.cjs → Toaster-Cummylmj.cjs} +2 -2
  202. package/dist/{Toaster-lv5cJhib.cjs.map → Toaster-Cummylmj.cjs.map} +1 -1
  203. package/dist/{Toaster-Dhz2mYq_.js → Toaster-cu5XyKeE.js} +2 -2
  204. package/dist/{Toaster-Dhz2mYq_.js.map → Toaster-cu5XyKeE.js.map} +1 -1
  205. package/dist/{TranslatedFields-BCJ86Tqp.cjs → TranslatedFields-CbTlgKnh.cjs} +2 -2
  206. package/dist/{TranslatedFields-BCJ86Tqp.cjs.map → TranslatedFields-CbTlgKnh.cjs.map} +1 -1
  207. package/dist/{TranslatedFields-BtNUAyrY.js → TranslatedFields-Ccjhq2YL.js} +5 -5
  208. package/dist/{TranslatedFields-BtNUAyrY.js.map → TranslatedFields-Ccjhq2YL.js.map} +1 -1
  209. package/dist/{UserCard-CiQUrZjb.cjs → UserCard-BfHHfkDr.cjs} +2 -2
  210. package/dist/{UserCard-CiQUrZjb.cjs.map → UserCard-BfHHfkDr.cjs.map} +1 -1
  211. package/dist/{UserCard-B-eNyZuT.js → UserCard-Bs8kuV2j.js} +3 -3
  212. package/dist/{UserCard-B-eNyZuT.js.map → UserCard-Bs8kuV2j.js.map} +1 -1
  213. package/dist/components/Alert/index.cjs +1 -1
  214. package/dist/components/Alert/index.js +1 -1
  215. package/dist/components/Breadcrumbs/index.cjs +1 -1
  216. package/dist/components/Breadcrumbs/index.js +1 -1
  217. package/dist/components/Button/index.cjs +1 -1
  218. package/dist/components/Button/index.js +1 -1
  219. package/dist/components/Card/index.cjs +1 -1
  220. package/dist/components/Card/index.js +1 -1
  221. package/dist/components/Chip/index.cjs +1 -1
  222. package/dist/components/Chip/index.js +1 -1
  223. package/dist/components/CodeBlock/index.cjs +1 -1
  224. package/dist/components/CodeBlock/index.js +1 -1
  225. package/dist/components/ColorPicker/index.cjs +1 -1
  226. package/dist/components/ColorPicker/index.js +1 -1
  227. package/dist/components/ColorRamp/index.cjs +1 -1
  228. package/dist/components/ColorRamp/index.js +1 -1
  229. package/dist/components/CopyButton/index.cjs +1 -1
  230. package/dist/components/CopyButton/index.js +1 -1
  231. package/dist/components/DatePicker/index.cjs +1 -1
  232. package/dist/components/DatePicker/index.js +1 -1
  233. package/dist/components/DateTimePicker/index.cjs +1 -1
  234. package/dist/components/DateTimePicker/index.js +1 -1
  235. package/dist/components/DescriptionList/index.cjs +1 -1
  236. package/dist/components/DescriptionList/index.js +1 -1
  237. package/dist/components/EmptyState/index.cjs +1 -1
  238. package/dist/components/EmptyState/index.js +1 -1
  239. package/dist/components/ErrorState/ErrorState.d.cts +13 -1
  240. package/dist/components/ErrorState/ErrorState.d.ts +13 -1
  241. package/dist/components/ErrorState/errorMessage.d.cts +12 -0
  242. package/dist/components/ErrorState/errorMessage.d.ts +12 -0
  243. package/dist/components/ErrorState/index.cjs +1 -1
  244. package/dist/components/ErrorState/index.d.cts +1 -1
  245. package/dist/components/ErrorState/index.d.ts +1 -1
  246. package/dist/components/ErrorState/index.js +6 -4
  247. package/dist/components/FileCard/index.cjs +1 -1
  248. package/dist/components/FileCard/index.js +1 -1
  249. package/dist/components/FileUploader/index.cjs +1 -1
  250. package/dist/components/FileUploader/index.js +1 -1
  251. package/dist/components/Flag/index.cjs +1 -1
  252. package/dist/components/Flag/index.js +1 -1
  253. package/dist/components/FullscreenToggle/index.cjs +1 -1
  254. package/dist/components/FullscreenToggle/index.js +1 -1
  255. package/dist/components/IconButton/index.cjs +1 -1
  256. package/dist/components/IconButton/index.js +1 -1
  257. package/dist/components/Loader/index.cjs +1 -1
  258. package/dist/components/Loader/index.js +1 -1
  259. package/dist/components/Modal/index.cjs +1 -1
  260. package/dist/components/Modal/index.js +1 -1
  261. package/dist/components/MultiSelect/index.cjs +1 -1
  262. package/dist/components/MultiSelect/index.js +1 -1
  263. package/dist/components/NumberField/index.cjs +1 -1
  264. package/dist/components/NumberField/index.js +1 -1
  265. package/dist/components/OtpField/index.cjs +1 -1
  266. package/dist/components/OtpField/index.js +1 -1
  267. package/dist/components/PageLayout/index.cjs +1 -1
  268. package/dist/components/PageLayout/index.js +1 -1
  269. package/dist/components/PageNotFound/index.cjs +1 -1
  270. package/dist/components/PageNotFound/index.js +1 -1
  271. package/dist/components/Pagination/index.cjs +1 -1
  272. package/dist/components/Pagination/index.js +1 -1
  273. package/dist/components/PaletteField/index.cjs +1 -1
  274. package/dist/components/PaletteField/index.js +1 -1
  275. package/dist/components/PhoneField/index.cjs +1 -1
  276. package/dist/components/PhoneField/index.js +1 -1
  277. package/dist/components/Popconfirm/index.cjs +1 -1
  278. package/dist/components/Popconfirm/index.js +1 -1
  279. package/dist/components/Progress/index.cjs +1 -1
  280. package/dist/components/Progress/index.js +1 -1
  281. package/dist/components/RemoveDialog/index.cjs +1 -1
  282. package/dist/components/RemoveDialog/index.js +1 -1
  283. package/dist/components/RichTextEditor/RichTextEditor.d.cts +16 -1
  284. package/dist/components/RichTextEditor/RichTextEditor.d.ts +16 -1
  285. package/dist/components/RichTextEditor/index.cjs +1 -1
  286. package/dist/components/RichTextEditor/index.js +1 -1
  287. package/dist/components/RootLayout/index.cjs +1 -1
  288. package/dist/components/RootLayout/index.js +1 -1
  289. package/dist/components/Select/index.cjs +1 -1
  290. package/dist/components/Select/index.js +1 -1
  291. package/dist/components/Sidebar/index.cjs +1 -1
  292. package/dist/components/Sidebar/index.js +1 -1
  293. package/dist/components/SpeedDial/index.cjs +1 -1
  294. package/dist/components/SpeedDial/index.js +1 -1
  295. package/dist/components/Stepper/index.cjs +1 -1
  296. package/dist/components/Stepper/index.js +1 -1
  297. package/dist/components/Table/index.cjs +1 -1
  298. package/dist/components/Table/index.js +1 -1
  299. package/dist/components/Tabs/index.cjs +1 -1
  300. package/dist/components/Tabs/index.js +1 -1
  301. package/dist/components/TagsField/index.cjs +1 -1
  302. package/dist/components/TagsField/index.js +1 -1
  303. package/dist/components/TextField/index.cjs +1 -1
  304. package/dist/components/TextField/index.js +1 -1
  305. package/dist/components/ThemeToggle/index.cjs +1 -1
  306. package/dist/components/ThemeToggle/index.js +1 -1
  307. package/dist/components/TimePicker/index.cjs +1 -1
  308. package/dist/components/TimePicker/index.js +1 -1
  309. package/dist/components/Toast/index.cjs +1 -1
  310. package/dist/components/Toast/index.js +1 -1
  311. package/dist/components/TranslatedFields/index.cjs +1 -1
  312. package/dist/components/TranslatedFields/index.js +1 -1
  313. package/dist/components/UserCard/index.cjs +1 -1
  314. package/dist/components/UserCard/index.js +1 -1
  315. package/dist/entries/app.cjs +1 -1
  316. package/dist/entries/app.js +1 -1
  317. package/dist/entries/components.cjs +1 -1
  318. package/dist/entries/components.js +144 -142
  319. package/dist/entries/hooks.cjs +1 -1
  320. package/dist/entries/hooks.d.cts +2 -0
  321. package/dist/entries/hooks.d.ts +2 -0
  322. package/dist/entries/hooks.js +9 -8
  323. package/dist/entries/i18n.cjs +1 -1
  324. package/dist/entries/i18n.js +2 -2
  325. package/dist/entries/theme.cjs +1 -1
  326. package/dist/entries/theme.js +1 -1
  327. package/dist/hooks/index.d.cts +2 -0
  328. package/dist/hooks/index.d.ts +2 -0
  329. package/dist/hooks/useTableQuery.d.cts +56 -0
  330. package/dist/hooks/useTableQuery.d.ts +56 -0
  331. package/dist/i18n/messages.d.cts +1 -0
  332. package/dist/i18n/messages.d.ts +1 -0
  333. package/dist/index.cjs +1 -1
  334. package/dist/index.css +1 -1
  335. package/dist/index.js +247 -244
  336. package/dist/{messages-BF2ft7yD.js → messages-DCefu6Pn.js} +20 -13
  337. package/dist/messages-DCefu6Pn.js.map +1 -0
  338. package/dist/messages-FiUqCKjJ.cjs +36 -0
  339. package/dist/messages-FiUqCKjJ.cjs.map +1 -0
  340. package/dist/useForm-CN-qCrP7.js +144 -0
  341. package/dist/useForm-CN-qCrP7.js.map +1 -0
  342. package/dist/useForm-WvV361y6.cjs +2 -0
  343. package/dist/useForm-WvV361y6.cjs.map +1 -0
  344. package/dist/{useOptionMenu-C0xSaZ4t.cjs → useOptionMenu-BoWyPgbY.cjs} +2 -2
  345. package/dist/{useOptionMenu-C0xSaZ4t.cjs.map → useOptionMenu-BoWyPgbY.cjs.map} +1 -1
  346. package/dist/{useOptionMenu-Cq_eHdab.js → useOptionMenu-D7EbYG9A.js} +3 -3
  347. package/dist/{useOptionMenu-Cq_eHdab.js.map → useOptionMenu-D7EbYG9A.js.map} +1 -1
  348. package/package.json +2 -1
  349. package/dist/ErrorBoundary-DJ6R1M9k.js +0 -126
  350. package/dist/ErrorBoundary-DJ6R1M9k.js.map +0 -1
  351. package/dist/ErrorBoundary-unvC1vZQ.cjs +0 -2
  352. package/dist/ErrorBoundary-unvC1vZQ.cjs.map +0 -1
  353. package/dist/RichTextEditor-DTz7Qcn_.cjs +0 -2
  354. package/dist/RichTextEditor-DTz7Qcn_.cjs.map +0 -1
  355. package/dist/RichTextEditor-fXcbUjTl.js +0 -806
  356. package/dist/RichTextEditor-fXcbUjTl.js.map +0 -1
  357. package/dist/messages-BF2ft7yD.js.map +0 -1
  358. package/dist/messages-ihnE1jVG.cjs +0 -36
  359. package/dist/messages-ihnE1jVG.cjs.map +0 -1
  360. package/dist/useForm-B_5wDIER.js +0 -126
  361. package/dist/useForm-B_5wDIER.js.map +0 -1
  362. package/dist/useForm-C7erBHt0.cjs +0 -2
  363. package/dist/useForm-C7erBHt0.cjs.map +0 -1
@@ -1,2 +1,2 @@
1
- "use strict";const c=require("react/jsx-runtime"),Q=require("clsx"),U=require("./FloatingPanel-BIC4WrFa.cjs"),$=require("./Icon-BVULqOJD.cjs"),H=require("./List-9lUjapQ5.cjs"),V=require("./Loader-D9nteBXt.cjs"),C=require("./Typography-B6ASPrzT.cjs"),G=require("./ConfigProvider-BElY0HuV.cjs"),l=require("react"),J="_popover_rf9kn_3",X="_search_rf9kn_11",Y="_searchIcon_rf9kn_20",Z="_searchInput_rf9kn_24",B="_listbox_rf9kn_40",ee="_active_rf9kn_48",te="_noOptions_rf9kn_52",re="_loading_rf9kn_58",se="_group_rf9kn_68",oe="_groupLabel_rf9kn_80",ne="_trailing_rf9kn_86",h={popover:J,search:X,searchIcon:Y,searchInput:Z,listbox:B,active:ee,noOptions:te,loading:re,group:se,groupLabel:oe,trailing:ne};function ae({menu:t,anchorRef:m,size:g,searchPlaceholder:_,loading:q=!1,loadingText:E,noOptionsText:d,showSelectedTick:x=!0,multiselectable:M=!1,labelledBy:j,ariaLabel:N,onSearchKeyDown:R,className:y}){const r=G.useT(),L=_??r("common.search"),{filteredOptions:I,highlightedIndex:O}=t,f=({opt:o,index:p})=>{const n=t.isSelected(o),u=n&&x;return c.jsx(H.ListItem,{id:t.optionId(p),role:"option",tabIndex:-1,"aria-selected":n,"aria-current":void 0,clickable:!0,selected:n,disabled:o.disabled,icon:o.icon,className:Q.clsx(p===O&&h.active),trailing:o.trailing!=null||u?c.jsxs("span",{className:h.trailing,children:[o.trailing,u&&c.jsx($.Icon,{name:"TickCircle",size:"sm"})]}):void 0,onMouseEnter:()=>!o.disabled&&t.setHighlightedIndex(p),onMouseDown:a=>a.preventDefault(),onClick:()=>t.pick(o),children:o.label},o.value)},b=o=>{if(!o.some(n=>n.opt.group!=null))return o.map(f);const p=[];for(const n of o){const u=p[p.length-1];u&&u.group===n.opt.group?u.rows.push(n):p.push({group:n.opt.group,rows:[n]})}return p.map((n,u)=>{if(n.group==null)return n.rows.map(f);const a=`${t.listboxId}-group-${u}`;return c.jsxs("div",{role:"group","aria-labelledby":a,className:h.group,children:[c.jsx(C.Typography,{as:"div",id:a,role:"presentation",variant:"caption",color:"muted",uppercase:!0,className:h.groupLabel,children:n.group}),n.rows.map(f)]},`group-${u}`)})};return c.jsxs(U.FloatingPanel,{ref:t.popoverRef,open:t.open,triggerRef:m,onClose:t.closeMenu,matchTriggerWidth:!0,className:Q.clsx(h.popover,y),children:[t.searchable&&c.jsxs("div",{className:h.search,children:[c.jsx($.Icon,{name:"SearchNormal",size:"sm",className:h.searchIcon,"aria-hidden":"true"}),c.jsx("input",{ref:t.searchInputRef,className:h.searchInput,type:"text",role:"combobox","aria-expanded":"true","aria-controls":t.listboxId,"aria-activedescendant":t.activeId,"aria-autocomplete":"list","aria-label":L,placeholder:L,value:t.searchQuery,spellCheck:!1,autoComplete:"off",onChange:o=>t.setSearchQuery(o.target.value),onKeyDown:R??t.handleKeyDown})]}),c.jsx(H.List,{role:"listbox",id:t.listboxId,"aria-labelledby":j,"aria-label":j?void 0:N,"aria-multiselectable":M||void 0,size:g,className:h.listbox,onMouseLeave:()=>t.setHighlightedIndex(-1),children:q?c.jsxs("div",{className:h.loading,children:[c.jsx(V.Loader,{size:"sm"}),c.jsx(C.Typography,{as:"span",variant:"bodySmall",color:"muted",children:E??r("common.loading")})]}):I.length===0?c.jsx("div",{className:h.noOptions,children:c.jsx(C.Typography,{as:"span",variant:"bodySmall",color:"muted",children:d==null?r("select.noOptions"):typeof d=="function"?d(t.searchQuery):d})}):b(I.map((o,p)=>({opt:o,index:p})))})]})}function ie(t){if(!t.some(g=>g.group!=null))return t;const m=new Map;for(const g of t){const _=m.get(g.group);_?_.push(g):m.set(g.group,[g])}return[...m.values()].flat()}function ce({idBase:t,options:m,isSelected:g,onPick:_,closeOnPick:q=!0,highlightSelected:E=!0,searchable:d=!1,onSearchChange:x,disabled:M=!1,focusRef:j,onClose:N}){const R=`${t}-listbox`,y=l.useCallback(e=>`${t}-opt-${e}`,[t]),[r,L]=l.useState(!1),[I,O]=l.useState(""),[f,b]=l.useState(-1),o=l.useRef(null),p=l.useRef(null),n=l.useRef({buffer:"",timer:0}),u=l.useRef(N);u.current=N;const a=l.useMemo(()=>{const e=I.trim().toLowerCase(),s=!d||x||!e?m:m.filter(i=>{var k;return i.label.toLowerCase().includes(e)||((k=i.keywords)==null?void 0:k.some(W=>W.toLowerCase().includes(e)))});return ie(s)},[d,x,I,m]),v=l.useCallback((e,s)=>{let i=e;for(;i>=0&&i<a.length;){if(!a[i].disabled)return i;i+=s}return-1},[a]),D=l.useCallback(e=>{var s,i;L(!1),O(""),window.clearTimeout(n.current.timer),n.current.buffer="",(s=u.current)==null||s.call(u),e&&((i=j.current)==null||i.focus())},[j]);l.useEffect(()=>{if(!r)return;const e=E?a.findIndex(g):-1;b(e>=0&&!a[e].disabled?e:v(0,1)),d&&requestAnimationFrame(()=>{var s;return(s=o.current)==null?void 0:s.focus()})},[r]),l.useEffect(()=>{var e,s;!r||f<0||(s=(e=document.getElementById(y(f)))==null?void 0:e.scrollIntoView)==null||s.call(e,{block:"nearest"})},[r,f,y]),l.useEffect(()=>{r&&d&&b(v(0,1))},[I]),l.useEffect(()=>{r&&b(e=>e<a.length?e:v(0,1))},[a.length]);const w=()=>{M||L(!0)},P=()=>r?D(!1):w(),S=e=>{O(e),x==null||x(e)},T=e=>{!e||e.disabled||(_(e),q&&D(!0))},K=e=>{b(s=>{const i=s<0?e>0?0:a.length-1:s+e,k=v(i,e);return k===-1?s:k})},z=e=>{const s=n.current;window.clearTimeout(s.timer),s.buffer+=e.toLowerCase(),s.timer=window.setTimeout(()=>s.buffer="",500);const i=a.findIndex(k=>!k.disabled&&k.label.toLowerCase().startsWith(s.buffer));i>=0&&b(i)},A=e=>{if(!M)switch(e.key){case"ArrowDown":e.preventDefault(),r?K(1):w();break;case"ArrowUp":e.preventDefault(),r?K(-1):w();break;case"Enter":e.preventDefault(),r?T(a[f]):w();break;case" ":r?d||(e.preventDefault(),T(a[f])):(e.preventDefault(),w());break;case"Escape":r&&(e.preventDefault(),e.stopPropagation(),D(!0));break;case"Tab":r&&D(!0);break;case"Home":r&&(e.preventDefault(),b(v(0,1)));break;case"End":r&&(e.preventDefault(),b(v(a.length-1,-1)));break;default:!d&&r&&e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&z(e.key)}},F=r&&f>=0?y(f):void 0;return{open:r,openMenu:w,closeMenu:D,toggleMenu:P,searchable:d,searchQuery:I,setSearchQuery:S,filteredOptions:a,highlightedIndex:f,setHighlightedIndex:b,isSelected:g,pick:T,handleKeyDown:A,listboxId:R,optionId:y,activeId:F,searchInputRef:o,popoverRef:p}}exports.OptionMenu=ae;exports.useOptionMenu=ce;
2
- //# sourceMappingURL=useOptionMenu-C0xSaZ4t.cjs.map
1
+ "use strict";const c=require("react/jsx-runtime"),Q=require("clsx"),U=require("./FloatingPanel-BIC4WrFa.cjs"),$=require("./Icon-BVULqOJD.cjs"),H=require("./List-9lUjapQ5.cjs"),V=require("./Loader-Cpr9-OOZ.cjs"),C=require("./Typography-B6ASPrzT.cjs"),G=require("./ConfigProvider-ByLHqXpv.cjs"),l=require("react"),J="_popover_rf9kn_3",X="_search_rf9kn_11",Y="_searchIcon_rf9kn_20",Z="_searchInput_rf9kn_24",B="_listbox_rf9kn_40",ee="_active_rf9kn_48",te="_noOptions_rf9kn_52",re="_loading_rf9kn_58",se="_group_rf9kn_68",oe="_groupLabel_rf9kn_80",ne="_trailing_rf9kn_86",h={popover:J,search:X,searchIcon:Y,searchInput:Z,listbox:B,active:ee,noOptions:te,loading:re,group:se,groupLabel:oe,trailing:ne};function ae({menu:t,anchorRef:m,size:g,searchPlaceholder:_,loading:q=!1,loadingText:E,noOptionsText:d,showSelectedTick:x=!0,multiselectable:M=!1,labelledBy:j,ariaLabel:N,onSearchKeyDown:R,className:y}){const r=G.useT(),L=_??r("common.search"),{filteredOptions:I,highlightedIndex:O}=t,f=({opt:o,index:p})=>{const n=t.isSelected(o),u=n&&x;return c.jsx(H.ListItem,{id:t.optionId(p),role:"option",tabIndex:-1,"aria-selected":n,"aria-current":void 0,clickable:!0,selected:n,disabled:o.disabled,icon:o.icon,className:Q.clsx(p===O&&h.active),trailing:o.trailing!=null||u?c.jsxs("span",{className:h.trailing,children:[o.trailing,u&&c.jsx($.Icon,{name:"TickCircle",size:"sm"})]}):void 0,onMouseEnter:()=>!o.disabled&&t.setHighlightedIndex(p),onMouseDown:a=>a.preventDefault(),onClick:()=>t.pick(o),children:o.label},o.value)},b=o=>{if(!o.some(n=>n.opt.group!=null))return o.map(f);const p=[];for(const n of o){const u=p[p.length-1];u&&u.group===n.opt.group?u.rows.push(n):p.push({group:n.opt.group,rows:[n]})}return p.map((n,u)=>{if(n.group==null)return n.rows.map(f);const a=`${t.listboxId}-group-${u}`;return c.jsxs("div",{role:"group","aria-labelledby":a,className:h.group,children:[c.jsx(C.Typography,{as:"div",id:a,role:"presentation",variant:"caption",color:"muted",uppercase:!0,className:h.groupLabel,children:n.group}),n.rows.map(f)]},`group-${u}`)})};return c.jsxs(U.FloatingPanel,{ref:t.popoverRef,open:t.open,triggerRef:m,onClose:t.closeMenu,matchTriggerWidth:!0,className:Q.clsx(h.popover,y),children:[t.searchable&&c.jsxs("div",{className:h.search,children:[c.jsx($.Icon,{name:"SearchNormal",size:"sm",className:h.searchIcon,"aria-hidden":"true"}),c.jsx("input",{ref:t.searchInputRef,className:h.searchInput,type:"text",role:"combobox","aria-expanded":"true","aria-controls":t.listboxId,"aria-activedescendant":t.activeId,"aria-autocomplete":"list","aria-label":L,placeholder:L,value:t.searchQuery,spellCheck:!1,autoComplete:"off",onChange:o=>t.setSearchQuery(o.target.value),onKeyDown:R??t.handleKeyDown})]}),c.jsx(H.List,{role:"listbox",id:t.listboxId,"aria-labelledby":j,"aria-label":j?void 0:N,"aria-multiselectable":M||void 0,size:g,className:h.listbox,onMouseLeave:()=>t.setHighlightedIndex(-1),children:q?c.jsxs("div",{className:h.loading,children:[c.jsx(V.Loader,{size:"sm"}),c.jsx(C.Typography,{as:"span",variant:"bodySmall",color:"muted",children:E??r("common.loading")})]}):I.length===0?c.jsx("div",{className:h.noOptions,children:c.jsx(C.Typography,{as:"span",variant:"bodySmall",color:"muted",children:d==null?r("select.noOptions"):typeof d=="function"?d(t.searchQuery):d})}):b(I.map((o,p)=>({opt:o,index:p})))})]})}function ie(t){if(!t.some(g=>g.group!=null))return t;const m=new Map;for(const g of t){const _=m.get(g.group);_?_.push(g):m.set(g.group,[g])}return[...m.values()].flat()}function ce({idBase:t,options:m,isSelected:g,onPick:_,closeOnPick:q=!0,highlightSelected:E=!0,searchable:d=!1,onSearchChange:x,disabled:M=!1,focusRef:j,onClose:N}){const R=`${t}-listbox`,y=l.useCallback(e=>`${t}-opt-${e}`,[t]),[r,L]=l.useState(!1),[I,O]=l.useState(""),[f,b]=l.useState(-1),o=l.useRef(null),p=l.useRef(null),n=l.useRef({buffer:"",timer:0}),u=l.useRef(N);u.current=N;const a=l.useMemo(()=>{const e=I.trim().toLowerCase(),s=!d||x||!e?m:m.filter(i=>{var k;return i.label.toLowerCase().includes(e)||((k=i.keywords)==null?void 0:k.some(W=>W.toLowerCase().includes(e)))});return ie(s)},[d,x,I,m]),v=l.useCallback((e,s)=>{let i=e;for(;i>=0&&i<a.length;){if(!a[i].disabled)return i;i+=s}return-1},[a]),D=l.useCallback(e=>{var s,i;L(!1),O(""),window.clearTimeout(n.current.timer),n.current.buffer="",(s=u.current)==null||s.call(u),e&&((i=j.current)==null||i.focus())},[j]);l.useEffect(()=>{if(!r)return;const e=E?a.findIndex(g):-1;b(e>=0&&!a[e].disabled?e:v(0,1)),d&&requestAnimationFrame(()=>{var s;return(s=o.current)==null?void 0:s.focus()})},[r]),l.useEffect(()=>{var e,s;!r||f<0||(s=(e=document.getElementById(y(f)))==null?void 0:e.scrollIntoView)==null||s.call(e,{block:"nearest"})},[r,f,y]),l.useEffect(()=>{r&&d&&b(v(0,1))},[I]),l.useEffect(()=>{r&&b(e=>e<a.length?e:v(0,1))},[a.length]);const w=()=>{M||L(!0)},P=()=>r?D(!1):w(),S=e=>{O(e),x==null||x(e)},T=e=>{!e||e.disabled||(_(e),q&&D(!0))},K=e=>{b(s=>{const i=s<0?e>0?0:a.length-1:s+e,k=v(i,e);return k===-1?s:k})},z=e=>{const s=n.current;window.clearTimeout(s.timer),s.buffer+=e.toLowerCase(),s.timer=window.setTimeout(()=>s.buffer="",500);const i=a.findIndex(k=>!k.disabled&&k.label.toLowerCase().startsWith(s.buffer));i>=0&&b(i)},A=e=>{if(!M)switch(e.key){case"ArrowDown":e.preventDefault(),r?K(1):w();break;case"ArrowUp":e.preventDefault(),r?K(-1):w();break;case"Enter":e.preventDefault(),r?T(a[f]):w();break;case" ":r?d||(e.preventDefault(),T(a[f])):(e.preventDefault(),w());break;case"Escape":r&&(e.preventDefault(),e.stopPropagation(),D(!0));break;case"Tab":r&&D(!0);break;case"Home":r&&(e.preventDefault(),b(v(0,1)));break;case"End":r&&(e.preventDefault(),b(v(a.length-1,-1)));break;default:!d&&r&&e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&z(e.key)}},F=r&&f>=0?y(f):void 0;return{open:r,openMenu:w,closeMenu:D,toggleMenu:P,searchable:d,searchQuery:I,setSearchQuery:S,filteredOptions:a,highlightedIndex:f,setHighlightedIndex:b,isSelected:g,pick:T,handleKeyDown:A,listboxId:R,optionId:y,activeId:F,searchInputRef:o,popoverRef:p}}exports.OptionMenu=ae;exports.useOptionMenu=ce;
2
+ //# sourceMappingURL=useOptionMenu-BoWyPgbY.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOptionMenu-C0xSaZ4t.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-BoWyPgbY.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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"}
@@ -3,9 +3,9 @@ import { clsx as P } from "clsx";
3
3
  import { F as J } from "./FloatingPanel-CeSOtE_D.js";
4
4
  import { I as j } from "./Icon-DaTvzLBu.js";
5
5
  import { L as X, a as Y } from "./List-CZwNGxuP.js";
6
- import { L as Z } from "./Loader-CwyoKoWY.js";
6
+ import { L as Z } from "./Loader-C1uaCtx6.js";
7
7
  import { T as C } from "./Typography-CJv5AnRP.js";
8
- import { a as B } from "./ConfigProvider-B_RSn9bb.js";
8
+ import { a as B } from "./ConfigProvider-BbsI15b-.js";
9
9
  import { useCallback as z, useState as A, useRef as T, useMemo as ee, useEffect as K } from "react";
10
10
  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 = {
11
11
  popover: re,
@@ -283,4 +283,4 @@ export {
283
283
  we as O,
284
284
  ye as u
285
285
  };
286
- //# sourceMappingURL=useOptionMenu-Cq_eHdab.js.map
286
+ //# sourceMappingURL=useOptionMenu-D7EbYG9A.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOptionMenu-Cq_eHdab.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-D7EbYG9A.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.28",
3
+ "version": "1.0.30",
4
4
  "description": "Techzy UI — reusable React component library for admin panels.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -127,6 +127,7 @@
127
127
  "scripts": {
128
128
  "build": "vite build && tsc -p tsconfig.build.json && node scripts/post-build.mjs",
129
129
  "build:icons": "node scripts/build-icons.mjs",
130
+ "docs:reference": "node scripts/build-reference.mjs && prettier --write COMPONENTS.md",
130
131
  "dev": "vite build --watch",
131
132
  "playground": "vite",
132
133
  "typecheck": "tsc --noEmit",
@@ -1,126 +0,0 @@
1
- import { jsx as i, jsxs as u } from "react/jsx-runtime";
2
- import { forwardRef as x, Component as R } from "react";
3
- import { clsx as j } from "clsx";
4
- import { B as C } from "./Button-BLW9yV8W.js";
5
- import { E as I } from "./EmptyState-BtwuzX9Z.js";
6
- import { I as B } from "./Icon-DaTvzLBu.js";
7
- import { a as h } from "./ConfigProvider-B_RSn9bb.js";
8
- function F(t, r = (e) => `Request failed (${e})`) {
9
- var a, m, c;
10
- if (t == null || t === !1) return;
11
- if (typeof t == "string") return t.trim() || void 0;
12
- if (typeof t != "object") return String(t);
13
- const e = t, s = (m = (a = e.response) == null ? void 0 : a.data) == null ? void 0 : m.message;
14
- if (typeof s == "string" && s.trim()) return s.trim();
15
- if (typeof e.message == "string" && e.message.trim()) return e.message.trim();
16
- const n = typeof e.status == "number" ? e.status : (c = e.response) == null ? void 0 : c.status;
17
- if (typeof n == "number") return r(n);
18
- }
19
- function O(t) {
20
- if (t != null) {
21
- if (t instanceof Error) return t.stack || `${t.name}: ${t.message}`;
22
- if (typeof t == "string") return t;
23
- try {
24
- return JSON.stringify(t, null, 2);
25
- } catch {
26
- return String(t);
27
- }
28
- }
29
- }
30
- const $ = "_errorState_aiagy_4", q = "_actions_aiagy_9", z = "_compact_aiagy_18", K = "_details_aiagy_23", M = "_summary_aiagy_29", V = "_pre_aiagy_36", o = {
31
- errorState: $,
32
- actions: q,
33
- compact: z,
34
- details: K,
35
- summary: M,
36
- pre: V
37
- }, w = typeof process < "u" && process.env.NODE_ENV !== "production", J = x(function({
38
- error: r,
39
- title: e,
40
- description: s,
41
- icon: n = "Danger",
42
- onRetry: a,
43
- retryLabel: m,
44
- showDetails: c = "dev",
45
- compact: p = !1,
46
- size: S,
47
- pattern: _,
48
- action: f,
49
- className: E,
50
- children: v,
51
- ...N
52
- }, D) {
53
- const l = h(), b = F(r, (k) => l("errorState.requestFailed", { status: k })), d = (c === "dev" ? w : c) ? O(r) : void 0, g = a != null ? /* @__PURE__ */ i(
54
- C,
55
- {
56
- size: "sm",
57
- variant: "outlined",
58
- color: "primary",
59
- startIcon: /* @__PURE__ */ i(B, { name: "RefreshRight" }),
60
- onClick: a,
61
- children: m ?? l("errorState.retry")
62
- }
63
- ) : null;
64
- return /* @__PURE__ */ u(
65
- I,
66
- {
67
- ref: D,
68
- role: "alert",
69
- "aria-live": "polite",
70
- color: "error",
71
- icon: n,
72
- title: e ?? l("errorState.title"),
73
- description: s ?? b ?? l("errorState.description"),
74
- size: S ?? (p ? "sm" : "md"),
75
- pattern: _ ?? !p,
76
- action: g || f ? /* @__PURE__ */ u("span", { className: o.actions, children: [
77
- g,
78
- f
79
- ] }) : void 0,
80
- className: j(o.errorState, p && o.compact, E),
81
- ...N,
82
- children: [
83
- d != null && /* @__PURE__ */ u("details", { className: o.details, children: [
84
- /* @__PURE__ */ i("summary", { className: o.summary, children: l("errorState.details") }),
85
- /* @__PURE__ */ i("pre", { className: o.pre, children: d })
86
- ] }),
87
- v
88
- ]
89
- }
90
- );
91
- }), T = (t = [], r = []) => t.length !== r.length || t.some((e, s) => !Object.is(e, r[s])), y = (t) => t instanceof Error ? t : new Error(String(t));
92
- function U({ error: t, reset: r }) {
93
- const e = h();
94
- return /* @__PURE__ */ i(J, { error: t, description: e("errorState.description"), onRetry: r });
95
- }
96
- class X extends R {
97
- constructor() {
98
- super(...arguments), this.state = { error: null }, this.reset = () => {
99
- var r, e;
100
- this.setState({ error: null }), (e = (r = this.props).onReset) == null || e.call(r);
101
- };
102
- }
103
- static getDerivedStateFromError(r) {
104
- return { error: y(r) };
105
- }
106
- componentDidCatch(r, e) {
107
- var s, n;
108
- (n = (s = this.props).onError) == null || n.call(s, y(r), e);
109
- }
110
- componentDidUpdate(r, e) {
111
- this.state.error && e.error && T(r.resetKeys, this.props.resetKeys) && this.reset();
112
- }
113
- render() {
114
- const { error: r } = this.state;
115
- if (!r) return this.props.children;
116
- const { fallback: e } = this.props;
117
- return typeof e == "function" ? e(r, this.reset) : e !== void 0 ? e : /* @__PURE__ */ i(U, { error: r, reset: this.reset });
118
- }
119
- }
120
- export {
121
- X as E,
122
- J as a,
123
- F as b,
124
- O as g
125
- };
126
- //# sourceMappingURL=ErrorBoundary-DJ6R1M9k.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErrorBoundary-DJ6R1M9k.js","sources":["../src/components/ErrorState/errorMessage.ts","../src/components/ErrorState/ErrorState.tsx","../src/components/ErrorState/ErrorBoundary.tsx"],"sourcesContent":["/**\n * Pull a human-readable message out of whatever was thrown / returned — the shapes admin apps actually see:\n *\n * 1. an axios-style error with a server body — `error.response.data.message` (the backend's own sentence)\n * 2. an `Error` (or anything with a string `message`) — `error.message`\n * 3. a raw HTTP response / status object — `{ status: 404, statusText }` → `\"Request failed (404)\"`\n * 4. a plain string\n *\n * Returns `undefined` when nothing usable is found (the caller shows its generic fallback). Pure — pass\n * `requestFailed` to localize case 3 (`{status}` is interpolated).\n */\nexport function getErrorMessage(\n error: unknown,\n requestFailed: (status: number) => string = (status) => `Request failed (${status})`,\n): string | undefined {\n if (error == null || error === false) return undefined\n if (typeof error === 'string') return error.trim() || undefined\n if (typeof error !== 'object') return String(error)\n\n const e = error as {\n message?: unknown\n status?: unknown\n response?: { data?: { message?: unknown }; status?: unknown }\n }\n const serverMessage = e.response?.data?.message\n if (typeof serverMessage === 'string' && serverMessage.trim()) return serverMessage.trim()\n if (typeof e.message === 'string' && e.message.trim()) return e.message.trim()\n const status = typeof e.status === 'number' ? e.status : e.response?.status\n if (typeof status === 'number') return requestFailed(status)\n return undefined\n}\n\n/** A stack / detail dump for the developer-facing details panel (Error → `name: message` + stack). */\nexport function getErrorDetails(error: unknown): string | undefined {\n if (error == null) return undefined\n if (error instanceof Error) return error.stack || `${error.name}: ${error.message}`\n if (typeof error === 'string') return error\n try {\n return JSON.stringify(error, null, 2)\n } catch {\n return String(error)\n }\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport { getErrorDetails, getErrorMessage } from './errorMessage'\nimport styles from './ErrorState.module.css'\n\n// `process.env.NODE_ENV` is inlined by every consumer bundler (React's own convention); declared locally\n// since the library ships without `@types/node`.\ndeclare const process: { env: { NODE_ENV?: string } } | undefined\nconst IS_DEV = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'\n\nexport interface ErrorStateProps extends Omit<EmptyStateProps, 'icon' | 'title' | 'color'> {\n /**\n * What failed — an `Error`, a string, an axios-style error, a `{ message }` or a raw `{ status }`\n * response. Its message becomes the description (unless `description` is given) and its stack feeds\n * the details panel.\n */\n error?: unknown\n /** Heading. Defaults to the localized \"Something went wrong\". */\n title?: ReactNode\n /** Leading icon — a known `IconName`, any node, or `false`. Defaults to `Danger`, tinted `error`. */\n icon?: IconName | ReactNode | false\n /** Adds a \"Try again\" button that calls this (e.g. a query's `refetch`). */\n onRetry?: () => void\n /** Retry button label. Defaults to the localized \"Try again\". */\n retryLabel?: ReactNode\n /**\n * Show a collapsible technical details panel (stack / raw error). `'dev'` (default) shows it only in\n * development builds; `true` always; `false` never.\n */\n showDetails?: boolean | 'dev'\n /** The inline variant — small, no hero pattern — for inside a table, card or panel. Defaults to `false`. */\n compact?: boolean\n}\n\n/**\n * The \"loading failed\" counterpart of `EmptyState` — a semantic preset over it: an `error`-tinted\n * `Danger` puck, a localized \"Something went wrong\" title, the failure's own message as the description\n * (extracted from an `Error`, a string, an axios-style `response.data.message`, a `{ message }`, or a raw\n * `{ status }` response → \"Request failed (404)\"), an optional **Try again** button (`onRetry`), and a\n * developer-only details panel with the stack (`showDetails`, default `'dev'`). `compact` is the inline\n * variant for a table / card. Announced to assistive tech (`role=\"alert\"`, `aria-live=\"polite\"`).\n * `forwardRef` to the root; any other `EmptyState` prop (`size`, `pattern`, `action`, …) passes through.\n */\nexport const ErrorState = forwardRef<HTMLDivElement, ErrorStateProps>(function ErrorState(\n {\n error,\n title,\n description,\n icon = 'Danger',\n onRetry,\n retryLabel,\n showDetails = 'dev',\n compact = false,\n size,\n pattern,\n action,\n className,\n children,\n ...props\n },\n ref,\n) {\n const t = useT()\n const message = getErrorMessage(error, (status) => t('errorState.requestFailed', { status }))\n const details = (showDetails === 'dev' ? IS_DEV : showDetails)\n ? getErrorDetails(error)\n : undefined\n\n const retry =\n onRetry != null ? (\n <Button\n size=\"sm\"\n variant=\"outlined\"\n color=\"primary\"\n startIcon={<Icon name=\"RefreshRight\" />}\n onClick={onRetry}\n >\n {retryLabel ?? t('errorState.retry')}\n </Button>\n ) : null\n\n return (\n <EmptyState\n ref={ref}\n role=\"alert\"\n aria-live=\"polite\"\n color=\"error\"\n icon={icon}\n title={title ?? t('errorState.title')}\n description={description ?? message ?? t('errorState.description')}\n size={size ?? (compact ? 'sm' : 'md')}\n pattern={pattern ?? !compact}\n action={\n retry || action ? (\n <span className={styles.actions}>\n {retry}\n {action}\n </span>\n ) : undefined\n }\n className={clsx(styles.errorState, compact && styles.compact, className)}\n {...props}\n >\n {details != null && (\n <details className={styles.details}>\n <summary className={styles.summary}>{t('errorState.details')}</summary>\n <pre className={styles.pre}>{details}</pre>\n </details>\n )}\n {children}\n </EmptyState>\n )\n})\n","import { Component, type ErrorInfo, type ReactNode } from 'react'\nimport { useT } from '../../theme'\nimport { ErrorState } from './ErrorState'\n\nexport interface ErrorBoundaryProps {\n /**\n * What to render after a crash — a node, or `(error, reset) => node`. Defaults to an `ErrorState` with\n * a friendly description, a **Try again** button (`reset`) and the stack in dev.\n */\n fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode)\n /** Report the crash (e.g. `Sentry.captureException`). */\n onError?: (error: Error, info: ErrorInfo) => void\n /** Called after the boundary resets (Try again, or a `resetKeys` change). */\n onReset?: () => void\n /** Reset automatically when any of these change (shallow) — e.g. `[location.pathname]` clears on navigation. */\n resetKeys?: unknown[]\n children?: ReactNode\n}\n\ninterface ErrorBoundaryState {\n error: Error | null\n}\n\nconst keysChanged = (a: unknown[] = [], b: unknown[] = []) =>\n a.length !== b.length || a.some((v, i) => !Object.is(v, b[i]))\n\nconst toError = (value: unknown) => (value instanceof Error ? value : new Error(String(value)))\n\n/** The default crash screen — a function component so it can read the localized strings. */\nfunction DefaultFallback({ error, reset }: { error: Error; reset: () => void }) {\n const t = useT()\n // a render crash message (\"Cannot read properties of undefined\") is for developers, not users —\n // the description stays friendly and the raw error lives in the dev-only details panel\n return <ErrorState error={error} description={t('errorState.description')} onRetry={reset} />\n}\n\n/**\n * Catches render errors in its subtree and shows a fallback instead of unmounting the whole app (a\n * white screen). The one class component in the library — React only offers error boundaries as\n * classes. `fallback` is a node or `(error, reset) => node` (default: an `ErrorState` with Try again);\n * `onError` reports the crash (Sentry); `resetKeys` resets it when they change (e.g. the route path, so\n * navigating away recovers); `onReset` runs after any reset. `AdminRoot` mounts one around the page\n * content automatically, so a crashing page keeps the sidebar + header.\n */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: unknown): ErrorBoundaryState {\n return { error: toError(error) }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError?.(toError(error), info)\n }\n\n componentDidUpdate(prev: ErrorBoundaryProps, prevState: ErrorBoundaryState) {\n // reset only an error that was ALREADY showing before the keys changed — if the key change itself is\n // what crashed the subtree (same render), resetting would just re-render it into a second throw\n if (this.state.error && prevState.error && keysChanged(prev.resetKeys, this.props.resetKeys)) {\n this.reset()\n }\n }\n\n reset = () => {\n this.setState({ error: null })\n this.props.onReset?.()\n }\n\n render() {\n const { error } = this.state\n if (!error) return this.props.children\n const { fallback } = this.props\n if (typeof fallback === 'function') return fallback(error, this.reset)\n if (fallback !== undefined) return fallback\n return <DefaultFallback error={error} reset={this.reset} />\n }\n}\n"],"names":["getErrorMessage","error","requestFailed","status","serverMessage","_b","_a","_c","getErrorDetails","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","size","pattern","action","className","children","props","ref","t","useT","message","details","retry","jsx","Button","Icon","jsxs","EmptyState","styles","clsx","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const n=require("react/jsx-runtime"),y=require("react"),k=require("clsx"),C=require("./Button-KRGjJdMV.cjs"),B=require("./EmptyState-CO_NRZ6w.cjs"),I=require("./Icon-BVULqOJD.cjs"),h=require("./ConfigProvider-BElY0HuV.cjs");function S(t,r=e=>`Request failed (${e})`){var a,l,c;if(t==null||t===!1)return;if(typeof t=="string")return t.trim()||void 0;if(typeof t!="object")return String(t);const e=t,s=(l=(a=e.response)==null?void 0:a.data)==null?void 0:l.message;if(typeof s=="string"&&s.trim())return s.trim();if(typeof e.message=="string"&&e.message.trim())return e.message.trim();const o=typeof e.status=="number"?e.status:(c=e.response)==null?void 0:c.status;if(typeof o=="number")return r(o)}function E(t){if(t!=null){if(t instanceof Error)return t.stack||`${t.name}: ${t.message}`;if(typeof t=="string")return t;try{return JSON.stringify(t,null,2)}catch{return String(t)}}}const F="_errorState_aiagy_4",M="_actions_aiagy_9",O="_compact_aiagy_18",$="_details_aiagy_23",z="_summary_aiagy_29",K="_pre_aiagy_36",i={errorState:F,actions:M,compact:O,details:$,summary:z,pre:K},T=typeof process<"u"&&process.env.NODE_ENV!=="production",_=y.forwardRef(function({error:r,title:e,description:s,icon:o="Danger",onRetry:a,retryLabel:l,showDetails:c="dev",compact:d=!1,size:v,pattern:x,action:p,className:j,children:q,...D},N){const u=h.useT(),R=S(r,b=>u("errorState.requestFailed",{status:b})),m=(c==="dev"?T:c)?E(r):void 0,f=a!=null?n.jsx(C.Button,{size:"sm",variant:"outlined",color:"primary",startIcon:n.jsx(I.Icon,{name:"RefreshRight"}),onClick:a,children:l??u("errorState.retry")}):null;return n.jsxs(B.EmptyState,{ref:N,role:"alert","aria-live":"polite",color:"error",icon:o,title:e??u("errorState.title"),description:s??R??u("errorState.description"),size:v??(d?"sm":"md"),pattern:x??!d,action:f||p?n.jsxs("span",{className:i.actions,children:[f,p]}):void 0,className:k.clsx(i.errorState,d&&i.compact,j),...D,children:[m!=null&&n.jsxs("details",{className:i.details,children:[n.jsx("summary",{className:i.summary,children:u("errorState.details")}),n.jsx("pre",{className:i.pre,children:m})]}),q]})}),V=(t=[],r=[])=>t.length!==r.length||t.some((e,s)=>!Object.is(e,r[s])),g=t=>t instanceof Error?t:new Error(String(t));function w({error:t,reset:r}){const e=h.useT();return n.jsx(_,{error:t,description:e("errorState.description"),onRetry:r})}class J extends y.Component{constructor(){super(...arguments),this.state={error:null},this.reset=()=>{var r,e;this.setState({error:null}),(e=(r=this.props).onReset)==null||e.call(r)}}static getDerivedStateFromError(r){return{error:g(r)}}componentDidCatch(r,e){var s,o;(o=(s=this.props).onError)==null||o.call(s,g(r),e)}componentDidUpdate(r,e){this.state.error&&e.error&&V(r.resetKeys,this.props.resetKeys)&&this.reset()}render(){const{error:r}=this.state;if(!r)return this.props.children;const{fallback:e}=this.props;return typeof e=="function"?e(r,this.reset):e!==void 0?e:n.jsx(w,{error:r,reset:this.reset})}}exports.ErrorBoundary=J;exports.ErrorState=_;exports.getErrorDetails=E;exports.getErrorMessage=S;
2
- //# sourceMappingURL=ErrorBoundary-unvC1vZQ.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErrorBoundary-unvC1vZQ.cjs","sources":["../src/components/ErrorState/errorMessage.ts","../src/components/ErrorState/ErrorState.tsx","../src/components/ErrorState/ErrorBoundary.tsx"],"sourcesContent":["/**\n * Pull a human-readable message out of whatever was thrown / returned — the shapes admin apps actually see:\n *\n * 1. an axios-style error with a server body — `error.response.data.message` (the backend's own sentence)\n * 2. an `Error` (or anything with a string `message`) — `error.message`\n * 3. a raw HTTP response / status object — `{ status: 404, statusText }` → `\"Request failed (404)\"`\n * 4. a plain string\n *\n * Returns `undefined` when nothing usable is found (the caller shows its generic fallback). Pure — pass\n * `requestFailed` to localize case 3 (`{status}` is interpolated).\n */\nexport function getErrorMessage(\n error: unknown,\n requestFailed: (status: number) => string = (status) => `Request failed (${status})`,\n): string | undefined {\n if (error == null || error === false) return undefined\n if (typeof error === 'string') return error.trim() || undefined\n if (typeof error !== 'object') return String(error)\n\n const e = error as {\n message?: unknown\n status?: unknown\n response?: { data?: { message?: unknown }; status?: unknown }\n }\n const serverMessage = e.response?.data?.message\n if (typeof serverMessage === 'string' && serverMessage.trim()) return serverMessage.trim()\n if (typeof e.message === 'string' && e.message.trim()) return e.message.trim()\n const status = typeof e.status === 'number' ? e.status : e.response?.status\n if (typeof status === 'number') return requestFailed(status)\n return undefined\n}\n\n/** A stack / detail dump for the developer-facing details panel (Error → `name: message` + stack). */\nexport function getErrorDetails(error: unknown): string | undefined {\n if (error == null) return undefined\n if (error instanceof Error) return error.stack || `${error.name}: ${error.message}`\n if (typeof error === 'string') return error\n try {\n return JSON.stringify(error, null, 2)\n } catch {\n return String(error)\n }\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport { getErrorDetails, getErrorMessage } from './errorMessage'\nimport styles from './ErrorState.module.css'\n\n// `process.env.NODE_ENV` is inlined by every consumer bundler (React's own convention); declared locally\n// since the library ships without `@types/node`.\ndeclare const process: { env: { NODE_ENV?: string } } | undefined\nconst IS_DEV = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'\n\nexport interface ErrorStateProps extends Omit<EmptyStateProps, 'icon' | 'title' | 'color'> {\n /**\n * What failed — an `Error`, a string, an axios-style error, a `{ message }` or a raw `{ status }`\n * response. Its message becomes the description (unless `description` is given) and its stack feeds\n * the details panel.\n */\n error?: unknown\n /** Heading. Defaults to the localized \"Something went wrong\". */\n title?: ReactNode\n /** Leading icon — a known `IconName`, any node, or `false`. Defaults to `Danger`, tinted `error`. */\n icon?: IconName | ReactNode | false\n /** Adds a \"Try again\" button that calls this (e.g. a query's `refetch`). */\n onRetry?: () => void\n /** Retry button label. Defaults to the localized \"Try again\". */\n retryLabel?: ReactNode\n /**\n * Show a collapsible technical details panel (stack / raw error). `'dev'` (default) shows it only in\n * development builds; `true` always; `false` never.\n */\n showDetails?: boolean | 'dev'\n /** The inline variant — small, no hero pattern — for inside a table, card or panel. Defaults to `false`. */\n compact?: boolean\n}\n\n/**\n * The \"loading failed\" counterpart of `EmptyState` — a semantic preset over it: an `error`-tinted\n * `Danger` puck, a localized \"Something went wrong\" title, the failure's own message as the description\n * (extracted from an `Error`, a string, an axios-style `response.data.message`, a `{ message }`, or a raw\n * `{ status }` response → \"Request failed (404)\"), an optional **Try again** button (`onRetry`), and a\n * developer-only details panel with the stack (`showDetails`, default `'dev'`). `compact` is the inline\n * variant for a table / card. Announced to assistive tech (`role=\"alert\"`, `aria-live=\"polite\"`).\n * `forwardRef` to the root; any other `EmptyState` prop (`size`, `pattern`, `action`, …) passes through.\n */\nexport const ErrorState = forwardRef<HTMLDivElement, ErrorStateProps>(function ErrorState(\n {\n error,\n title,\n description,\n icon = 'Danger',\n onRetry,\n retryLabel,\n showDetails = 'dev',\n compact = false,\n size,\n pattern,\n action,\n className,\n children,\n ...props\n },\n ref,\n) {\n const t = useT()\n const message = getErrorMessage(error, (status) => t('errorState.requestFailed', { status }))\n const details = (showDetails === 'dev' ? IS_DEV : showDetails)\n ? getErrorDetails(error)\n : undefined\n\n const retry =\n onRetry != null ? (\n <Button\n size=\"sm\"\n variant=\"outlined\"\n color=\"primary\"\n startIcon={<Icon name=\"RefreshRight\" />}\n onClick={onRetry}\n >\n {retryLabel ?? t('errorState.retry')}\n </Button>\n ) : null\n\n return (\n <EmptyState\n ref={ref}\n role=\"alert\"\n aria-live=\"polite\"\n color=\"error\"\n icon={icon}\n title={title ?? t('errorState.title')}\n description={description ?? message ?? t('errorState.description')}\n size={size ?? (compact ? 'sm' : 'md')}\n pattern={pattern ?? !compact}\n action={\n retry || action ? (\n <span className={styles.actions}>\n {retry}\n {action}\n </span>\n ) : undefined\n }\n className={clsx(styles.errorState, compact && styles.compact, className)}\n {...props}\n >\n {details != null && (\n <details className={styles.details}>\n <summary className={styles.summary}>{t('errorState.details')}</summary>\n <pre className={styles.pre}>{details}</pre>\n </details>\n )}\n {children}\n </EmptyState>\n )\n})\n","import { Component, type ErrorInfo, type ReactNode } from 'react'\nimport { useT } from '../../theme'\nimport { ErrorState } from './ErrorState'\n\nexport interface ErrorBoundaryProps {\n /**\n * What to render after a crash — a node, or `(error, reset) => node`. Defaults to an `ErrorState` with\n * a friendly description, a **Try again** button (`reset`) and the stack in dev.\n */\n fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode)\n /** Report the crash (e.g. `Sentry.captureException`). */\n onError?: (error: Error, info: ErrorInfo) => void\n /** Called after the boundary resets (Try again, or a `resetKeys` change). */\n onReset?: () => void\n /** Reset automatically when any of these change (shallow) — e.g. `[location.pathname]` clears on navigation. */\n resetKeys?: unknown[]\n children?: ReactNode\n}\n\ninterface ErrorBoundaryState {\n error: Error | null\n}\n\nconst keysChanged = (a: unknown[] = [], b: unknown[] = []) =>\n a.length !== b.length || a.some((v, i) => !Object.is(v, b[i]))\n\nconst toError = (value: unknown) => (value instanceof Error ? value : new Error(String(value)))\n\n/** The default crash screen — a function component so it can read the localized strings. */\nfunction DefaultFallback({ error, reset }: { error: Error; reset: () => void }) {\n const t = useT()\n // a render crash message (\"Cannot read properties of undefined\") is for developers, not users —\n // the description stays friendly and the raw error lives in the dev-only details panel\n return <ErrorState error={error} description={t('errorState.description')} onRetry={reset} />\n}\n\n/**\n * Catches render errors in its subtree and shows a fallback instead of unmounting the whole app (a\n * white screen). The one class component in the library — React only offers error boundaries as\n * classes. `fallback` is a node or `(error, reset) => node` (default: an `ErrorState` with Try again);\n * `onError` reports the crash (Sentry); `resetKeys` resets it when they change (e.g. the route path, so\n * navigating away recovers); `onReset` runs after any reset. `AdminRoot` mounts one around the page\n * content automatically, so a crashing page keeps the sidebar + header.\n */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: unknown): ErrorBoundaryState {\n return { error: toError(error) }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError?.(toError(error), info)\n }\n\n componentDidUpdate(prev: ErrorBoundaryProps, prevState: ErrorBoundaryState) {\n // reset only an error that was ALREADY showing before the keys changed — if the key change itself is\n // what crashed the subtree (same render), resetting would just re-render it into a second throw\n if (this.state.error && prevState.error && keysChanged(prev.resetKeys, this.props.resetKeys)) {\n this.reset()\n }\n }\n\n reset = () => {\n this.setState({ error: null })\n this.props.onReset?.()\n }\n\n render() {\n const { error } = this.state\n if (!error) return this.props.children\n const { fallback } = this.props\n if (typeof fallback === 'function') return fallback(error, this.reset)\n if (fallback !== undefined) return fallback\n return <DefaultFallback error={error} reset={this.reset} />\n }\n}\n"],"names":["getErrorMessage","error","requestFailed","status","serverMessage","_b","_a","_c","getErrorDetails","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","size","pattern","action","className","children","props","ref","t","useT","message","details","retry","jsx","Button","Icon","jsxs","EmptyState","styles","clsx","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"6OAWO,SAASA,EACdC,EACAC,EAA6CC,GAAW,mBAAmBA,CAAM,IAC7D,WACpB,GAAIF,GAAS,MAAQA,IAAU,GAAO,OACtC,GAAI,OAAOA,GAAU,SAAU,OAAOA,EAAM,QAAU,OACtD,GAAI,OAAOA,GAAU,SAAU,OAAO,OAAOA,CAAK,EAElD,MAAM,EAAIA,EAKJG,GAAgBC,GAAAC,EAAA,EAAE,WAAF,YAAAA,EAAY,OAAZ,YAAAD,EAAkB,QACxC,GAAI,OAAOD,GAAkB,UAAYA,EAAc,OAAQ,OAAOA,EAAc,KAAA,EACpF,GAAI,OAAO,EAAE,SAAY,UAAY,EAAE,QAAQ,OAAQ,OAAO,EAAE,QAAQ,KAAA,EACxE,MAAMD,EAAS,OAAO,EAAE,QAAW,SAAW,EAAE,QAASI,EAAA,EAAE,WAAF,YAAAA,EAAY,OACrE,GAAI,OAAOJ,GAAW,SAAU,OAAOD,EAAcC,CAAM,CAE7D,CAGO,SAASK,EAAgBP,EAAoC,CAClE,GAAIA,GAAS,KACb,IAAIA,aAAiB,MAAO,OAAOA,EAAM,OAAS,GAAGA,EAAM,IAAI,KAAKA,EAAM,OAAO,GACjF,GAAI,OAAOA,GAAU,SAAU,OAAOA,EACtC,GAAI,CACF,OAAO,KAAK,UAAUA,EAAO,KAAM,CAAC,CACtC,MAAQ,CACN,OAAO,OAAOA,CAAK,CACrB,EACF,uMC7BMQ,EAAS,OAAO,QAAY,KAAe,QAAQ,IAAI,WAAa,aAmC7DC,EAAaC,EAAAA,WAA4C,SACpE,CACE,MAAAV,EACA,MAAAW,EACA,YAAAC,EACA,KAAAC,EAAO,SACP,QAAAC,EACA,WAAAC,EACA,YAAAC,EAAc,MACd,QAAAC,EAAU,GACV,KAAAC,EACA,QAAAC,EACA,OAAAC,EACA,UAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,MAAMC,EAAIC,EAAAA,KAAA,EACJC,EAAU5B,EAAgBC,EAAQE,GAAWuB,EAAE,2BAA4B,CAAE,OAAAvB,CAAA,CAAQ,CAAC,EACtF0B,GAAWZ,IAAgB,MAAQR,EAASQ,GAC9CT,EAAgBP,CAAK,EACrB,OAEE6B,EACJf,GAAW,KACTgB,EAAAA,IAACC,EAAAA,OAAA,CACC,KAAK,KACL,QAAQ,WACR,MAAM,UACN,UAAWD,EAAAA,IAACE,EAAAA,KAAA,CAAK,KAAK,cAAA,CAAe,EACrC,QAASlB,EAER,SAAAC,GAAcU,EAAE,kBAAkB,CAAA,CAAA,EAEnC,KAEN,OACEQ,EAAAA,KAACC,EAAAA,WAAA,CACC,IAAAV,EACA,KAAK,QACL,YAAU,SACV,MAAM,QACN,KAAAX,EACA,MAAOF,GAASc,EAAE,kBAAkB,EACpC,YAAab,GAAee,GAAWF,EAAE,wBAAwB,EACjE,KAAMP,IAASD,EAAU,KAAO,MAChC,QAASE,GAAW,CAACF,EACrB,OACEY,GAAST,SACN,OAAA,CAAK,UAAWe,EAAO,QACrB,SAAA,CAAAN,EACAT,CAAA,CAAA,CACH,EACE,OAEN,UAAWgB,EAAAA,KAAKD,EAAO,WAAYlB,GAAWkB,EAAO,QAASd,CAAS,EACtE,GAAGE,EAEH,SAAA,CAAAK,GAAW,MACVK,EAAAA,KAAC,UAAA,CAAQ,UAAWE,EAAO,QACzB,SAAA,CAAAL,MAAC,WAAQ,UAAWK,EAAO,QAAU,SAAAV,EAAE,oBAAoB,EAAE,EAC7DK,EAAAA,IAAC,MAAA,CAAI,UAAWK,EAAO,IAAM,SAAAP,CAAA,CAAQ,CAAA,EACvC,EAEDN,CAAA,CAAA,CAAA,CAGP,CAAC,EC9FKe,EAAc,CAACC,EAAe,CAAA,EAAIC,EAAe,CAAA,IACrDD,EAAE,SAAWC,EAAE,QAAUD,EAAE,KAAK,CAACE,EAAGC,IAAM,CAAC,OAAO,GAAGD,EAAGD,EAAEE,CAAC,CAAC,CAAC,EAEzDC,EAAWC,GAAoBA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAG7F,SAASC,EAAgB,CAAE,MAAA5C,EAAO,MAAA6C,GAA8C,CAC9E,MAAMpB,EAAIC,EAAAA,KAAA,EAGV,OAAOI,EAAAA,IAACrB,GAAW,MAAAT,EAAc,YAAayB,EAAE,wBAAwB,EAAG,QAASoB,EAAO,CAC7F,CAUO,MAAMC,UAAsBC,EAAAA,SAAkD,CAA9E,aAAA,CAAA,MAAA,GAAA,SAAA,EACL,KAAA,MAA4B,CAAE,MAAO,IAAA,EAkBrC,KAAA,MAAQ,IAAM,SACZ,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,GAC7B3C,GAAAC,EAAA,KAAK,OAAM,UAAX,MAAAD,EAAA,KAAAC,EACF,CAAA,CAnBA,OAAO,yBAAyBL,EAAoC,CAClE,MAAO,CAAE,MAAO0C,EAAQ1C,CAAK,CAAA,CAC/B,CAEA,kBAAkBA,EAAgBgD,EAAiB,UACjD5C,GAAAC,EAAA,KAAK,OAAM,UAAX,MAAAD,EAAA,KAAAC,EAAqBqC,EAAQ1C,CAAK,EAAGgD,EACvC,CAEA,mBAAmBC,EAA0BC,EAA+B,CAGtE,KAAK,MAAM,OAASA,EAAU,OAASb,EAAYY,EAAK,UAAW,KAAK,MAAM,SAAS,GACzF,KAAK,MAAA,CAET,CAOA,QAAS,CACP,KAAM,CAAE,MAAAjD,GAAU,KAAK,MACvB,GAAI,CAACA,EAAO,OAAO,KAAK,MAAM,SAC9B,KAAM,CAAE,SAAAmD,GAAa,KAAK,MAC1B,OAAI,OAAOA,GAAa,WAAmBA,EAASnD,EAAO,KAAK,KAAK,EACjEmD,IAAa,OAAkBA,EAC5BrB,EAAAA,IAACc,EAAA,CAAgB,MAAA5C,EAAc,MAAO,KAAK,MAAO,CAC3D,CACF"}