@techzyapp/ui-library 1.0.31 → 1.0.32
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.
- package/dist/{AdminRoot-BYkmCGNx.js → AdminRoot-B9A4Hoz0.js} +5 -5
- package/dist/{AdminRoot-BYkmCGNx.js.map → AdminRoot-B9A4Hoz0.js.map} +1 -1
- package/dist/{AdminRoot-BbkfFQEn.cjs → AdminRoot-BVUEWczU.cjs} +2 -2
- package/dist/{AdminRoot-BbkfFQEn.cjs.map → AdminRoot-BVUEWczU.cjs.map} +1 -1
- package/dist/{Alert-BLqAcEoT.js → Alert-B7w9xD2p.js} +3 -3
- package/dist/{Alert-BLqAcEoT.js.map → Alert-B7w9xD2p.js.map} +1 -1
- package/dist/{Alert-BM5WOI_u.cjs → Alert-B9l1VhIr.cjs} +2 -2
- package/dist/{Alert-BM5WOI_u.cjs.map → Alert-B9l1VhIr.cjs.map} +1 -1
- package/dist/{Breadcrumbs-Di4-Acfb.cjs → Breadcrumbs-B1JMwCjO.cjs} +2 -2
- package/dist/{Breadcrumbs-Di4-Acfb.cjs.map → Breadcrumbs-B1JMwCjO.cjs.map} +1 -1
- package/dist/{Breadcrumbs-CzHGbN2c.js → Breadcrumbs-Cl1CgKkk.js} +3 -3
- package/dist/{Breadcrumbs-CzHGbN2c.js.map → Breadcrumbs-Cl1CgKkk.js.map} +1 -1
- package/dist/{Button-9Qcdkw-y.js → Button-BJ5Xd10u.js} +2 -2
- package/dist/{Button-9Qcdkw-y.js.map → Button-BJ5Xd10u.js.map} +1 -1
- package/dist/{Button-BQhiJq8e.cjs → Button-BZq1mIUH.cjs} +2 -2
- package/dist/{Button-BQhiJq8e.cjs.map → Button-BZq1mIUH.cjs.map} +1 -1
- package/dist/{Calendar-dXhLgOUH.cjs → Calendar-r-dDXWEp.cjs} +2 -2
- package/dist/{Calendar-dXhLgOUH.cjs.map → Calendar-r-dDXWEp.cjs.map} +1 -1
- package/dist/{Calendar-BB-C0qXO.js → Calendar-rRPnaU9M.js} +3 -3
- package/dist/{Calendar-BB-C0qXO.js.map → Calendar-rRPnaU9M.js.map} +1 -1
- package/dist/{Card-BERQfyhJ.js → Card-Cr3D2bzJ.js} +2 -2
- package/dist/{Card-BERQfyhJ.js.map → Card-Cr3D2bzJ.js.map} +1 -1
- package/dist/{Card-DULpoOfj.cjs → Card-KsczbH5c.cjs} +2 -2
- package/dist/{Card-DULpoOfj.cjs.map → Card-KsczbH5c.cjs.map} +1 -1
- package/dist/{Chip-BuydTI6V.cjs → Chip-BZ3I4Lbe.cjs} +2 -2
- package/dist/{Chip-BuydTI6V.cjs.map → Chip-BZ3I4Lbe.cjs.map} +1 -1
- package/dist/{Chip-DZ5Fz7jx.js → Chip-DEp1zWh1.js} +2 -2
- package/dist/{Chip-DZ5Fz7jx.js.map → Chip-DEp1zWh1.js.map} +1 -1
- package/dist/{CodeBlock-BySsTAtY.js → CodeBlock-CMHqvoBJ.js} +3 -3
- package/dist/{CodeBlock-BySsTAtY.js.map → CodeBlock-CMHqvoBJ.js.map} +1 -1
- package/dist/{CodeBlock-BPraYPoS.cjs → CodeBlock-DIkyeG4S.cjs} +2 -2
- package/dist/{CodeBlock-BPraYPoS.cjs.map → CodeBlock-DIkyeG4S.cjs.map} +1 -1
- package/dist/{ColorPicker-DJow7m2v.js → ColorPicker-5SMyU5oh.js} +3 -3
- package/dist/{ColorPicker-DJow7m2v.js.map → ColorPicker-5SMyU5oh.js.map} +1 -1
- package/dist/{ColorPicker-BTBTQD39.cjs → ColorPicker-B1riGs1z.cjs} +2 -2
- package/dist/{ColorPicker-BTBTQD39.cjs.map → ColorPicker-B1riGs1z.cjs.map} +1 -1
- package/dist/{ColorPickerPanel-D6agWM6y.js → ColorPickerPanel-4Y6oXL7v.js} +2 -2
- package/dist/{ColorPickerPanel-D6agWM6y.js.map → ColorPickerPanel-4Y6oXL7v.js.map} +1 -1
- package/dist/{ColorPickerPanel-DXIYwUoE.cjs → ColorPickerPanel-CzBlh0zw.cjs} +2 -2
- package/dist/{ColorPickerPanel-DXIYwUoE.cjs.map → ColorPickerPanel-CzBlh0zw.cjs.map} +1 -1
- package/dist/{ColorRamp-B45Rtwgw.cjs → ColorRamp-D_h-hp7n.cjs} +2 -2
- package/dist/{ColorRamp-B45Rtwgw.cjs.map → ColorRamp-D_h-hp7n.cjs.map} +1 -1
- package/dist/{ColorRamp-Bhj28c_6.js → ColorRamp-Qc8ZtPDh.js} +2 -2
- package/dist/{ColorRamp-Bhj28c_6.js.map → ColorRamp-Qc8ZtPDh.js.map} +1 -1
- package/dist/ConfigProvider-CzAQf_d_.cjs +2 -0
- package/dist/ConfigProvider-CzAQf_d_.cjs.map +1 -0
- package/dist/ConfigProvider-D2svpXFu.js +347 -0
- package/dist/ConfigProvider-D2svpXFu.js.map +1 -0
- package/dist/{CopyButton-CBk85MQ7.js → CopyButton-BNcW9-KU.js} +3 -3
- package/dist/{CopyButton-CBk85MQ7.js.map → CopyButton-BNcW9-KU.js.map} +1 -1
- package/dist/{CopyButton-Bfte6TJF.cjs → CopyButton-DUtx2-Gi.cjs} +2 -2
- package/dist/{CopyButton-Bfte6TJF.cjs.map → CopyButton-DUtx2-Gi.cjs.map} +1 -1
- package/dist/{DatePicker-eAzDnO2Y.js → DatePicker-D2PyGdec.js} +4 -4
- package/dist/{DatePicker-eAzDnO2Y.js.map → DatePicker-D2PyGdec.js.map} +1 -1
- package/dist/{DatePicker-DBiU4Mb6.cjs → DatePicker-D_PqDvKt.cjs} +2 -2
- package/dist/{DatePicker-DBiU4Mb6.cjs.map → DatePicker-D_PqDvKt.cjs.map} +1 -1
- package/dist/{DateTimePicker-CvaD8IkF.cjs → DateTimePicker-C3Kq5hKE.cjs} +2 -2
- package/dist/{DateTimePicker-CvaD8IkF.cjs.map → DateTimePicker-C3Kq5hKE.cjs.map} +1 -1
- package/dist/{DateTimePicker-M2UBjFVc.js → DateTimePicker-DdXFzqO_.js} +7 -7
- package/dist/{DateTimePicker-M2UBjFVc.js.map → DateTimePicker-DdXFzqO_.js.map} +1 -1
- package/dist/{DescriptionList-DQHNOTWl.cjs → DescriptionList-C7AOcw_2.cjs} +2 -2
- package/dist/{DescriptionList-DQHNOTWl.cjs.map → DescriptionList-C7AOcw_2.cjs.map} +1 -1
- package/dist/{DescriptionList-BhsmdtS1.js → DescriptionList-DxRgKNEJ.js} +4 -4
- package/dist/{DescriptionList-BhsmdtS1.js.map → DescriptionList-DxRgKNEJ.js.map} +1 -1
- package/dist/{Dropdown-BbaU1WDC.cjs → Dropdown-CMqWq6J_.cjs} +2 -2
- package/dist/{Dropdown-BbaU1WDC.cjs.map → Dropdown-CMqWq6J_.cjs.map} +1 -1
- package/dist/{Dropdown-BlmbYp1X.js → Dropdown-zlv96RLy.js} +2 -2
- package/dist/{Dropdown-BlmbYp1X.js.map → Dropdown-zlv96RLy.js.map} +1 -1
- package/dist/{EmptyState-2pA3XlOX.js → EmptyState-CvpKSYY4.js} +2 -2
- package/dist/{EmptyState-2pA3XlOX.js.map → EmptyState-CvpKSYY4.js.map} +1 -1
- package/dist/{EmptyState-ByBpy2vN.cjs → EmptyState-ECc6e_En.cjs} +2 -2
- package/dist/{EmptyState-ByBpy2vN.cjs.map → EmptyState-ECc6e_En.cjs.map} +1 -1
- package/dist/{ErrorBoundary-B-37hGZW.js → ErrorBoundary-CJx5E9wJ.js} +5 -5
- package/dist/{ErrorBoundary-B-37hGZW.js.map → ErrorBoundary-CJx5E9wJ.js.map} +1 -1
- package/dist/{ErrorBoundary-gRGxeuM1.cjs → ErrorBoundary-DbKRtdgS.cjs} +2 -2
- package/dist/{ErrorBoundary-gRGxeuM1.cjs.map → ErrorBoundary-DbKRtdgS.cjs.map} +1 -1
- package/dist/{FileCard-BYNJVmp0.cjs → FileCard-Bjqsgi7S.cjs} +2 -2
- package/dist/{FileCard-BYNJVmp0.cjs.map → FileCard-Bjqsgi7S.cjs.map} +1 -1
- package/dist/{FileCard-BNfUAgsF.js → FileCard-D4t0-ms2.js} +3 -3
- package/dist/{FileCard-BNfUAgsF.js.map → FileCard-D4t0-ms2.js.map} +1 -1
- package/dist/{FileUploader-DdICa5UC.cjs → FileUploader-DWM8WrY6.cjs} +2 -2
- package/dist/{FileUploader-DdICa5UC.cjs.map → FileUploader-DWM8WrY6.cjs.map} +1 -1
- package/dist/{FileUploader-TOWwDOSS.js → FileUploader-DdcvZoUb.js} +5 -5
- package/dist/{FileUploader-TOWwDOSS.js.map → FileUploader-DdcvZoUb.js.map} +1 -1
- package/dist/{Flag-DDR6OANA.js → Flag-BLEBMdb-.js} +2 -2
- package/dist/{Flag-DDR6OANA.js.map → Flag-BLEBMdb-.js.map} +1 -1
- package/dist/{Flag-DXPQ2t8z.cjs → Flag-D5rqScYG.cjs} +2 -2
- package/dist/{Flag-DXPQ2t8z.cjs.map → Flag-D5rqScYG.cjs.map} +1 -1
- package/dist/{FullscreenToggle-BKo1lDSE.cjs → FullscreenToggle-CZoc5pYg.cjs} +2 -2
- package/dist/{FullscreenToggle-BKo1lDSE.cjs.map → FullscreenToggle-CZoc5pYg.cjs.map} +1 -1
- package/dist/{FullscreenToggle-DmH1541W.js → FullscreenToggle-DZnKK1Lj.js} +3 -3
- package/dist/{FullscreenToggle-DmH1541W.js.map → FullscreenToggle-DZnKK1Lj.js.map} +1 -1
- package/dist/{IconButton-CL_6iMQh.js → IconButton-CqFgam3J.js} +2 -2
- package/dist/{IconButton-CL_6iMQh.js.map → IconButton-CqFgam3J.js.map} +1 -1
- package/dist/{IconButton-CvIXSFsr.cjs → IconButton-V8tjArlt.cjs} +2 -2
- package/dist/{IconButton-CvIXSFsr.cjs.map → IconButton-V8tjArlt.cjs.map} +1 -1
- package/dist/List-CXHlAI5w.js +38 -0
- package/dist/List-CXHlAI5w.js.map +1 -0
- package/dist/List-DOsh6w-d.cjs +2 -0
- package/dist/List-DOsh6w-d.cjs.map +1 -0
- package/dist/ListItem-CUeIBhOF.cjs +2 -0
- package/dist/ListItem-CUeIBhOF.cjs.map +1 -0
- package/dist/ListItem-ehFB7TUW.js +77 -0
- package/dist/ListItem-ehFB7TUW.js.map +1 -0
- package/dist/{Loader-Czzb450N.js → Loader-Bsz0BkGr.js} +2 -2
- package/dist/{Loader-Czzb450N.js.map → Loader-Bsz0BkGr.js.map} +1 -1
- package/dist/{Loader-CI1j71X8.cjs → Loader-CqRaCdzF.cjs} +2 -2
- package/dist/{Loader-CI1j71X8.cjs.map → Loader-CqRaCdzF.cjs.map} +1 -1
- package/dist/LocationPicker-BRGNcTd_.cjs +2 -0
- package/dist/LocationPicker-BRGNcTd_.cjs.map +1 -0
- package/dist/LocationPicker-DtMDpPFZ.js +781 -0
- package/dist/LocationPicker-DtMDpPFZ.js.map +1 -0
- package/dist/{Modal-DPObz0b-.cjs → Modal-CcrqM4kn.cjs} +2 -2
- package/dist/{Modal-DPObz0b-.cjs.map → Modal-CcrqM4kn.cjs.map} +1 -1
- package/dist/{Modal-DMJMw6kT.js → Modal-DCee1a9m.js} +3 -3
- package/dist/{Modal-DMJMw6kT.js.map → Modal-DCee1a9m.js.map} +1 -1
- package/dist/{MultiSelect-IDAJ5a5K.cjs → MultiSelect-BJ-qMpA5.cjs} +2 -2
- package/dist/{MultiSelect-IDAJ5a5K.cjs.map → MultiSelect-BJ-qMpA5.cjs.map} +1 -1
- package/dist/{MultiSelect-BTR6w5Ot.js → MultiSelect-JQ6iKHyI.js} +4 -4
- package/dist/{MultiSelect-BTR6w5Ot.js.map → MultiSelect-JQ6iKHyI.js.map} +1 -1
- package/dist/{NumberField-DlaW-g3Z.js → NumberField-Bf-vDNLy.js} +3 -3
- package/dist/{NumberField-DlaW-g3Z.js.map → NumberField-Bf-vDNLy.js.map} +1 -1
- package/dist/{NumberField-Cg0XEDgW.cjs → NumberField-mZjwZB8E.cjs} +2 -2
- package/dist/{NumberField-Cg0XEDgW.cjs.map → NumberField-mZjwZB8E.cjs.map} +1 -1
- package/dist/{OtpField-vxQuo-uR.js → OtpField-DaAIBp6C.js} +2 -2
- package/dist/{OtpField-vxQuo-uR.js.map → OtpField-DaAIBp6C.js.map} +1 -1
- package/dist/{OtpField-DsedK1nQ.cjs → OtpField-TdjMkgQi.cjs} +2 -2
- package/dist/{OtpField-DsedK1nQ.cjs.map → OtpField-TdjMkgQi.cjs.map} +1 -1
- package/dist/{PageLayout-BPbjTYS3.cjs → PageLayout-BoHvt2cT.cjs} +2 -2
- package/dist/{PageLayout-BPbjTYS3.cjs.map → PageLayout-BoHvt2cT.cjs.map} +1 -1
- package/dist/{PageLayout-Rk6KSxmn.js → PageLayout-Bwv8Oohb.js} +2 -2
- package/dist/{PageLayout-Rk6KSxmn.js.map → PageLayout-Bwv8Oohb.js.map} +1 -1
- package/dist/{PageNotFound-CBNhKZ9Y.js → PageNotFound-CMt8vnky.js} +5 -5
- package/dist/{PageNotFound-CBNhKZ9Y.js.map → PageNotFound-CMt8vnky.js.map} +1 -1
- package/dist/{PageNotFound-PUQ1o9R4.cjs → PageNotFound-DDm6nwQh.cjs} +2 -2
- package/dist/{PageNotFound-PUQ1o9R4.cjs.map → PageNotFound-DDm6nwQh.cjs.map} +1 -1
- package/dist/{Pagination-CNdkfXp2.js → Pagination-C0xr3D-g.js} +2 -2
- package/dist/{Pagination-CNdkfXp2.js.map → Pagination-C0xr3D-g.js.map} +1 -1
- package/dist/{Pagination-DNGKNQy0.cjs → Pagination-DzkTjEZL.cjs} +2 -2
- package/dist/{Pagination-DNGKNQy0.cjs.map → Pagination-DzkTjEZL.cjs.map} +1 -1
- package/dist/{PaletteField-BSIF5jI6.cjs → PaletteField-CQV2dll0.cjs} +2 -2
- package/dist/{PaletteField-BSIF5jI6.cjs.map → PaletteField-CQV2dll0.cjs.map} +1 -1
- package/dist/{PaletteField-Bp5Fgygh.js → PaletteField-CQv6MBKe.js} +3 -3
- package/dist/{PaletteField-Bp5Fgygh.js.map → PaletteField-CQv6MBKe.js.map} +1 -1
- package/dist/{PhoneField-BdmvslXQ.js → PhoneField-Bqj5-33G.js} +4 -4
- package/dist/{PhoneField-BdmvslXQ.js.map → PhoneField-Bqj5-33G.js.map} +1 -1
- package/dist/{PhoneField-BMhZeZkW.cjs → PhoneField-Dzdm5hfY.cjs} +2 -2
- package/dist/{PhoneField-BMhZeZkW.cjs.map → PhoneField-Dzdm5hfY.cjs.map} +1 -1
- package/dist/{Popconfirm-Cyaeybtj.js → Popconfirm-CYkwGTh-.js} +3 -3
- package/dist/{Popconfirm-Cyaeybtj.js.map → Popconfirm-CYkwGTh-.js.map} +1 -1
- package/dist/{Popconfirm-IhlIINtZ.cjs → Popconfirm-DS6tCxV0.cjs} +2 -2
- package/dist/{Popconfirm-IhlIINtZ.cjs.map → Popconfirm-DS6tCxV0.cjs.map} +1 -1
- package/dist/{Progress-T7PLrJ0Y.js → Progress-DZUtn3Sh.js} +2 -2
- package/dist/{Progress-T7PLrJ0Y.js.map → Progress-DZUtn3Sh.js.map} +1 -1
- package/dist/{Progress-CAY1p06_.cjs → Progress-lf9vIKIk.cjs} +2 -2
- package/dist/{Progress-CAY1p06_.cjs.map → Progress-lf9vIKIk.cjs.map} +1 -1
- package/dist/{QueryError-Dtspj9l4.js → QueryError-Dl8yzdxw.js} +2 -2
- package/dist/{QueryError-Dtspj9l4.js.map → QueryError-Dl8yzdxw.js.map} +1 -1
- package/dist/{QueryError-DP22IUnp.cjs → QueryError-RF7Mh5zg.cjs} +2 -2
- package/dist/{QueryError-DP22IUnp.cjs.map → QueryError-RF7Mh5zg.cjs.map} +1 -1
- package/dist/{RemoveDialog-D12B4x80.cjs → RemoveDialog-Csfhv9ve.cjs} +2 -2
- package/dist/{RemoveDialog-D12B4x80.cjs.map → RemoveDialog-Csfhv9ve.cjs.map} +1 -1
- package/dist/{RemoveDialog-DdGsqaWV.js → RemoveDialog-DaWh4xmW.js} +5 -5
- package/dist/{RemoveDialog-DdGsqaWV.js.map → RemoveDialog-DaWh4xmW.js.map} +1 -1
- package/dist/{RichTextEditor-DL4y5xVv.js → RichTextEditor-BLEDQq2H.js} +9 -9
- package/dist/{RichTextEditor-DL4y5xVv.js.map → RichTextEditor-BLEDQq2H.js.map} +1 -1
- package/dist/RichTextEditor-Eo8uLXlI.cjs +2 -0
- package/dist/{RichTextEditor-BVXY25sz.cjs.map → RichTextEditor-Eo8uLXlI.cjs.map} +1 -1
- package/dist/RootLayout-BvyeNM9_.cjs +2 -0
- package/dist/{RootLayout-DDuzPlJe.cjs.map → RootLayout-BvyeNM9_.cjs.map} +1 -1
- package/dist/{RootLayout-BK3t6Mm0.js → RootLayout-D-ZlsTXF.js} +23 -23
- package/dist/{RootLayout-BK3t6Mm0.js.map → RootLayout-D-ZlsTXF.js.map} +1 -1
- package/dist/{Select-tVI_qer3.js → Select-C0UBQXhg.js} +3 -3
- package/dist/{Select-tVI_qer3.js.map → Select-C0UBQXhg.js.map} +1 -1
- package/dist/{Select-DlFDOZtn.cjs → Select-CH3mF6y1.cjs} +2 -2
- package/dist/{Select-DlFDOZtn.cjs.map → Select-CH3mF6y1.cjs.map} +1 -1
- package/dist/{Sidebar-CjrD3nNp.js → Sidebar--rOPtrqa.js} +33 -32
- package/dist/{Sidebar-CjrD3nNp.js.map → Sidebar--rOPtrqa.js.map} +1 -1
- package/dist/Sidebar-6wu2fuPT.cjs +2 -0
- package/dist/{Sidebar-gB-X4VLX.cjs.map → Sidebar-6wu2fuPT.cjs.map} +1 -1
- package/dist/{SpeedDial-xQr4JH0x.js → SpeedDial-BIodC6td.js} +2 -2
- package/dist/{SpeedDial-xQr4JH0x.js.map → SpeedDial-BIodC6td.js.map} +1 -1
- package/dist/{SpeedDial-BIOkkLKO.cjs → SpeedDial-BtxXH6Ij.cjs} +2 -2
- package/dist/{SpeedDial-BIOkkLKO.cjs.map → SpeedDial-BtxXH6Ij.cjs.map} +1 -1
- package/dist/{Stepper-CBdhvPoz.cjs → Stepper-B38I8PBS.cjs} +2 -2
- package/dist/{Stepper-CBdhvPoz.cjs.map → Stepper-B38I8PBS.cjs.map} +1 -1
- package/dist/{Stepper-CkYcIc15.js → Stepper-CPBPTxbP.js} +13 -13
- package/dist/{Stepper-CkYcIc15.js.map → Stepper-CPBPTxbP.js.map} +1 -1
- package/dist/Table-1RVWzyS6.cjs +2 -0
- package/dist/{Table-Cwxqo7Br.cjs.map → Table-1RVWzyS6.cjs.map} +1 -1
- package/dist/{Table-CwQKfXGn.js → Table-BV-dr36o.js} +45 -45
- package/dist/{Table-CwQKfXGn.js.map → Table-BV-dr36o.js.map} +1 -1
- package/dist/{Tabs-651xbRe4.cjs → Tabs-DIs8iFA-.cjs} +2 -2
- package/dist/{Tabs-651xbRe4.cjs.map → Tabs-DIs8iFA-.cjs.map} +1 -1
- package/dist/{Tabs-Bztnezt9.js → Tabs-RjyUkLTB.js} +10 -10
- package/dist/{Tabs-Bztnezt9.js.map → Tabs-RjyUkLTB.js.map} +1 -1
- package/dist/{TagsField-CdymON69.js → TagsField-B3MtFiFs.js} +4 -4
- package/dist/{TagsField-CdymON69.js.map → TagsField-B3MtFiFs.js.map} +1 -1
- package/dist/{TagsField-B7ZARHzD.cjs → TagsField-CJ10-kFr.cjs} +2 -2
- package/dist/{TagsField-B7ZARHzD.cjs.map → TagsField-CJ10-kFr.cjs.map} +1 -1
- package/dist/{TextField-DkaYK1DI.js → TextField-CInaL0FR.js} +3 -3
- package/dist/{TextField-DkaYK1DI.js.map → TextField-CInaL0FR.js.map} +1 -1
- package/dist/{TextField-B22NRQ91.cjs → TextField-D_hzd5Gf.cjs} +2 -2
- package/dist/{TextField-B22NRQ91.cjs.map → TextField-D_hzd5Gf.cjs.map} +1 -1
- package/dist/ThemeToggle-CWfuK0tZ.js +28 -0
- package/dist/{ThemeToggle-DqzUvcK5.js.map → ThemeToggle-CWfuK0tZ.js.map} +1 -1
- package/dist/{ThemeToggle-D5dWHQFb.cjs → ThemeToggle-DkhhlH_r.cjs} +2 -2
- package/dist/{ThemeToggle-D5dWHQFb.cjs.map → ThemeToggle-DkhhlH_r.cjs.map} +1 -1
- package/dist/{TimeColumns-BEoHh961.js → TimeColumns-fD6dosYP.js} +2 -2
- package/dist/{TimeColumns-BEoHh961.js.map → TimeColumns-fD6dosYP.js.map} +1 -1
- package/dist/{TimeColumns-o2xhvSGE.cjs → TimeColumns-t3Pn01v5.cjs} +2 -2
- package/dist/{TimeColumns-o2xhvSGE.cjs.map → TimeColumns-t3Pn01v5.cjs.map} +1 -1
- package/dist/{TimePicker-CACmHwNn.cjs → TimePicker-DOwQF7sX.cjs} +2 -2
- package/dist/{TimePicker-CACmHwNn.cjs.map → TimePicker-DOwQF7sX.cjs.map} +1 -1
- package/dist/{TimePicker-DCryZCmh.js → TimePicker-DypTHDW0.js} +5 -5
- package/dist/{TimePicker-DCryZCmh.js.map → TimePicker-DypTHDW0.js.map} +1 -1
- package/dist/{Toaster-DwVLab3k.js → Toaster-BwNAKDMc.js} +2 -2
- package/dist/{Toaster-DwVLab3k.js.map → Toaster-BwNAKDMc.js.map} +1 -1
- package/dist/{Toaster-BwREV06e.cjs → Toaster-DdUOwi7L.cjs} +2 -2
- package/dist/{Toaster-BwREV06e.cjs.map → Toaster-DdUOwi7L.cjs.map} +1 -1
- package/dist/{TranslatedFields-B0LMXgiu.js → TranslatedFields-C_-qPixE.js} +13 -13
- package/dist/{TranslatedFields-B0LMXgiu.js.map → TranslatedFields-C_-qPixE.js.map} +1 -1
- package/dist/{TranslatedFields-sio1Qfy7.cjs → TranslatedFields-D9FQlxiQ.cjs} +2 -2
- package/dist/{TranslatedFields-sio1Qfy7.cjs.map → TranslatedFields-D9FQlxiQ.cjs.map} +1 -1
- package/dist/{UserCard-Dzc4zmPj.cjs → UserCard-C-q2s2Cw.cjs} +2 -2
- package/dist/{UserCard-Dzc4zmPj.cjs.map → UserCard-C-q2s2Cw.cjs.map} +1 -1
- package/dist/{UserCard-B5FVcJaK.js → UserCard-CwWv0HXD.js} +3 -3
- package/dist/{UserCard-B5FVcJaK.js.map → UserCard-CwWv0HXD.js.map} +1 -1
- package/dist/components/Alert/index.cjs +1 -1
- package/dist/components/Alert/index.js +1 -1
- package/dist/components/Breadcrumbs/index.cjs +1 -1
- package/dist/components/Breadcrumbs/index.js +1 -1
- package/dist/components/Button/index.cjs +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/Card/index.cjs +1 -1
- package/dist/components/Card/index.js +1 -1
- package/dist/components/Chip/index.cjs +1 -1
- package/dist/components/Chip/index.js +1 -1
- package/dist/components/CodeBlock/index.cjs +1 -1
- package/dist/components/CodeBlock/index.js +1 -1
- package/dist/components/ColorPicker/index.cjs +1 -1
- package/dist/components/ColorPicker/index.js +1 -1
- package/dist/components/ColorRamp/index.cjs +1 -1
- package/dist/components/ColorRamp/index.js +1 -1
- package/dist/components/CopyButton/index.cjs +1 -1
- package/dist/components/CopyButton/index.js +1 -1
- package/dist/components/DatePicker/index.cjs +1 -1
- package/dist/components/DatePicker/index.js +1 -1
- package/dist/components/DateTimePicker/index.cjs +1 -1
- package/dist/components/DateTimePicker/index.js +1 -1
- package/dist/components/DescriptionList/index.cjs +1 -1
- package/dist/components/DescriptionList/index.js +1 -1
- package/dist/components/Dropdown/index.cjs +1 -1
- package/dist/components/Dropdown/index.js +1 -1
- package/dist/components/EmptyState/index.cjs +1 -1
- package/dist/components/EmptyState/index.js +1 -1
- package/dist/components/ErrorState/index.cjs +1 -1
- package/dist/components/ErrorState/index.js +2 -2
- package/dist/components/FileCard/index.cjs +1 -1
- package/dist/components/FileCard/index.js +1 -1
- package/dist/components/FileUploader/index.cjs +1 -1
- package/dist/components/FileUploader/index.js +1 -1
- package/dist/components/Flag/index.cjs +1 -1
- package/dist/components/Flag/index.js +1 -1
- package/dist/components/FullscreenToggle/index.cjs +1 -1
- package/dist/components/FullscreenToggle/index.js +1 -1
- package/dist/components/IconButton/index.cjs +1 -1
- package/dist/components/IconButton/index.js +1 -1
- package/dist/components/List/index.cjs +1 -1
- package/dist/components/List/index.js +5 -4
- package/dist/components/List/index.js.map +1 -1
- package/dist/components/Loader/index.cjs +1 -1
- package/dist/components/Loader/index.js +1 -1
- package/dist/components/LocationPicker/LocationPicker.d.cts +87 -0
- package/dist/components/LocationPicker/LocationPicker.d.ts +87 -0
- package/dist/components/LocationPicker/PlaceSearch.d.cts +20 -0
- package/dist/components/LocationPicker/PlaceSearch.d.ts +20 -0
- package/dist/components/LocationPicker/googleMaps.d.cts +89 -0
- package/dist/components/LocationPicker/googleMaps.d.ts +89 -0
- package/dist/components/LocationPicker/index.cjs +2 -0
- package/dist/components/LocationPicker/index.cjs.map +1 -0
- package/dist/components/LocationPicker/index.d.cts +2 -0
- package/dist/components/LocationPicker/index.d.ts +2 -0
- package/dist/components/LocationPicker/index.js +7 -0
- package/dist/components/LocationPicker/index.js.map +1 -0
- package/dist/components/Modal/index.cjs +1 -1
- package/dist/components/Modal/index.js +1 -1
- package/dist/components/MultiSelect/index.cjs +1 -1
- package/dist/components/MultiSelect/index.js +1 -1
- package/dist/components/NumberField/index.cjs +1 -1
- package/dist/components/NumberField/index.js +1 -1
- package/dist/components/OtpField/index.cjs +1 -1
- package/dist/components/OtpField/index.js +1 -1
- package/dist/components/PageLayout/index.cjs +1 -1
- package/dist/components/PageLayout/index.js +1 -1
- package/dist/components/PageNotFound/index.cjs +1 -1
- package/dist/components/PageNotFound/index.js +1 -1
- package/dist/components/Pagination/index.cjs +1 -1
- package/dist/components/Pagination/index.js +1 -1
- package/dist/components/PaletteField/index.cjs +1 -1
- package/dist/components/PaletteField/index.js +1 -1
- package/dist/components/PhoneField/index.cjs +1 -1
- package/dist/components/PhoneField/index.js +1 -1
- package/dist/components/Popconfirm/index.cjs +1 -1
- package/dist/components/Popconfirm/index.js +1 -1
- package/dist/components/Progress/index.cjs +1 -1
- package/dist/components/Progress/index.js +1 -1
- package/dist/components/RemoveDialog/index.cjs +1 -1
- package/dist/components/RemoveDialog/index.js +1 -1
- package/dist/components/RichTextEditor/index.cjs +1 -1
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/components/RootLayout/index.cjs +1 -1
- package/dist/components/RootLayout/index.js +1 -1
- package/dist/components/Select/index.cjs +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/Sidebar/index.cjs +1 -1
- package/dist/components/Sidebar/index.js +1 -1
- package/dist/components/SpeedDial/index.cjs +1 -1
- package/dist/components/SpeedDial/index.js +1 -1
- package/dist/components/Stepper/index.cjs +1 -1
- package/dist/components/Stepper/index.js +1 -1
- package/dist/components/Table/index.cjs +1 -1
- package/dist/components/Table/index.js +1 -1
- package/dist/components/Tabs/index.cjs +1 -1
- package/dist/components/Tabs/index.js +1 -1
- package/dist/components/TagsField/index.cjs +1 -1
- package/dist/components/TagsField/index.js +1 -1
- package/dist/components/TextField/index.cjs +1 -1
- package/dist/components/TextField/index.js +1 -1
- package/dist/components/ThemeToggle/index.cjs +1 -1
- package/dist/components/ThemeToggle/index.js +1 -1
- package/dist/components/TimePicker/index.cjs +1 -1
- package/dist/components/TimePicker/index.js +1 -1
- package/dist/components/Toast/index.cjs +1 -1
- package/dist/components/Toast/index.js +1 -1
- package/dist/components/TranslatedFields/index.cjs +1 -1
- package/dist/components/TranslatedFields/index.js +1 -1
- package/dist/components/UserCard/index.cjs +1 -1
- package/dist/components/UserCard/index.js +1 -1
- package/dist/components/index.d.cts +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/entries/app.cjs +1 -1
- package/dist/entries/app.js +1 -1
- package/dist/entries/components.cjs +1 -1
- package/dist/entries/components.js +136 -132
- package/dist/entries/components.js.map +1 -1
- package/dist/entries/i18n.cjs +1 -1
- package/dist/entries/i18n.js +2 -2
- package/dist/entries/theme.cjs +1 -1
- package/dist/entries/theme.d.cts +2 -2
- package/dist/entries/theme.d.ts +2 -2
- package/dist/entries/theme.js +15 -13
- package/dist/i18n/messages.d.cts +42 -0
- package/dist/i18n/messages.d.ts +42 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +238 -232
- package/dist/index.js.map +1 -1
- package/dist/{messages-DswDgGe2.js → messages-BOJsnD0O.js} +180 -33
- package/dist/messages-BOJsnD0O.js.map +1 -0
- package/dist/{messages-DS38X5W2.cjs → messages-ejfYfHwL.cjs} +9 -9
- package/dist/messages-ejfYfHwL.cjs.map +1 -0
- package/dist/theme/ConfigProvider.d.cts +22 -0
- package/dist/theme/ConfigProvider.d.ts +22 -0
- package/dist/theme/index.d.cts +2 -2
- package/dist/theme/index.d.ts +2 -2
- package/dist/useOptionMenu-8hjCTNL4.cjs +2 -0
- package/dist/{useOptionMenu-BYeSUee6.cjs.map → useOptionMenu-8hjCTNL4.cjs.map} +1 -1
- package/dist/{useOptionMenu-DtTvY9EC.js → useOptionMenu-C1wOZ9NT.js} +9 -8
- package/dist/{useOptionMenu-DtTvY9EC.js.map → useOptionMenu-C1wOZ9NT.js.map} +1 -1
- package/package.json +1 -1
- package/dist/ConfigProvider-Ct0Pe3Ku.js +0 -335
- package/dist/ConfigProvider-Ct0Pe3Ku.js.map +0 -1
- package/dist/ConfigProvider-CtpfSy1i.cjs +0 -2
- package/dist/ConfigProvider-CtpfSy1i.cjs.map +0 -1
- package/dist/List-BLPB3-B8.js +0 -107
- package/dist/List-BLPB3-B8.js.map +0 -1
- package/dist/List-ah2PNWeY.cjs +0 -2
- package/dist/List-ah2PNWeY.cjs.map +0 -1
- package/dist/RichTextEditor-BVXY25sz.cjs +0 -2
- package/dist/RootLayout-DDuzPlJe.cjs +0 -2
- package/dist/Sidebar-gB-X4VLX.cjs +0 -2
- package/dist/Table-Cwxqo7Br.cjs +0 -2
- package/dist/ThemeToggle-DqzUvcK5.js +0 -28
- package/dist/messages-DS38X5W2.cjs.map +0 -1
- package/dist/messages-DswDgGe2.js.map +0 -1
- package/dist/useOptionMenu-BYeSUee6.cjs +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown-BbaU1WDC.cjs","sources":["../src/components/Dropdown/Dropdown.tsx"],"sourcesContent":["import {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { List, type ListItemSize } from '../List'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Dropdown.module.css'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface Position {\n top: number\n left: number\n side: 'top' | 'bottom'\n maxHeight: number\n minWidth?: number\n}\n\nexport interface DropdownProps {\n /** The element that opens the menu (e.g. a `Button` / `IconButton`). Cloned to wire click + a11y. */\n trigger: ReactElement\n /** Menu content — typically `ListItem`s (composed inside a `role=\"menu\"` `List`). */\n children: ReactNode\n /** Preferred placement. Flips to the opposite side automatically when it would overflow. Default `bottom-start`. */\n placement?: DropdownPlacement\n /** Menu size — sets the panel min-width (`sm` 150 · `md` 190 · `lg` 220) and the items' density. Default `md`. */\n size?: ListItemSize\n /**\n * Apply the size-based min-width (`sm` 150 · `md` 190 · `lg` 220px). Defaults to `true`; set `false`\n * to let the menu size to its content instead (the items' density still tracks `size`).\n */\n minWidth?: boolean\n /** Controlled open state. */\n open?: boolean\n /** Initial open state for uncontrolled use. Defaults to `false`. */\n defaultOpen?: boolean\n /** Fires with the next open state. */\n onOpenChange?: (open: boolean) => void\n /** Close the menu when an item inside is clicked. Defaults to `true`. */\n closeOnSelect?: boolean\n /** Make the menu at least as wide as the trigger (select-like). Defaults to `false`. */\n matchTriggerWidth?: boolean\n /** Prevents opening. */\n disabled?: boolean\n /** Gap between the trigger and the menu, in px. Defaults to `6`. */\n offset?: number\n /** Class applied to the floating panel. */\n className?: string\n /** Style applied to the floating panel. */\n style?: CSSProperties\n}\n\n/** Distance the menu is kept from the viewport edges (px). */\nconst VIEWPORT_PADDING = 8\n/** Focusable menu items, used for arrow-key roving. */\nconst FOCUSABLE =\n '[role=\"menuitem\"],[role=\"button\"],a[href],button:not([disabled]),[tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableItems(panel: HTMLElement | null): HTMLElement[] {\n if (!panel) return []\n return Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.getAttribute('aria-disabled') !== 'true' && el.offsetParent !== null,\n )\n}\n\n/**\n * A floating menu anchored to a `trigger`. Opens on trigger click; closes on outside click, `Escape`,\n * or selecting an item. The panel is portaled to `document.body` and positioned with collision\n * handling — it **flips** to the opposite side when it would overflow, clamps within the viewport, and\n * re-positions on scroll/resize (a too-tall menu caps its height and scrolls). Arrow keys move between\n * items; `Escape` returns focus to the trigger. Compose `ListItem`s as `children`.\n */\nexport function Dropdown({\n trigger,\n children,\n placement = 'bottom-start',\n size = 'md',\n minWidth = true,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnSelect = true,\n matchTriggerWidth = false,\n disabled = false,\n offset = 6,\n className,\n style,\n}: DropdownProps) {\n const menuId = useId()\n const triggerRef = useRef<HTMLElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n const isControlled = open !== undefined\n const [internalOpen, setInternalOpen] = useState(defaultOpen)\n const isOpen = isControlled ? open : internalOpen\n const [visible, setVisible] = useState(false)\n const [pos, setPos] = useState<Position | null>(null)\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n const close = useCallback(() => setOpen(false), [setOpen])\n\n // lock page scroll while the menu is open (no scrollbar shift)\n useLockBodyScroll(isOpen)\n\n // ── positioning: flip when it would overflow, clamp inside the viewport ──\n const update = useCallback(() => {\n const triggerEl = triggerRef.current\n const panel = panelRef.current\n if (!triggerEl || !panel) return\n\n const rect = triggerEl.getBoundingClientRect()\n const panelW = panel.offsetWidth\n const panelH = panel.offsetHeight\n const vw = window.innerWidth\n const vh = window.innerHeight\n const pad = VIEWPORT_PADDING\n\n const spaceBelow = vh - rect.bottom - offset - pad\n const spaceAbove = rect.top - offset - pad\n let side: 'top' | 'bottom' = placement.startsWith('bottom') ? 'bottom' : 'top'\n // flip only when the preferred side can't fit AND the opposite side has more room\n if (side === 'bottom' && panelH > spaceBelow && spaceAbove > spaceBelow) side = 'top'\n else if (side === 'top' && panelH > spaceAbove && spaceBelow > spaceAbove) side = 'bottom'\n\n const available = side === 'bottom' ? spaceBelow : spaceAbove\n const maxHeight = Math.max(0, available)\n const usedH = Math.min(panelH, maxHeight)\n\n let top = side === 'bottom' ? rect.bottom + offset : rect.top - offset - usedH\n top = Math.min(Math.max(top, pad), Math.max(pad, vh - pad - usedH))\n\n let left = placement.endsWith('end') ? rect.right - panelW : rect.left\n left = Math.min(Math.max(left, pad), Math.max(pad, vw - pad - panelW))\n\n setPos({ top, left, side, maxHeight, minWidth: matchTriggerWidth ? rect.width : undefined })\n }, [placement, offset, matchTriggerWidth])\n\n // position synchronously before paint whenever the menu is open\n useLayoutEffect(() => {\n if (!isOpen) {\n setVisible(false)\n return\n }\n update()\n }, [isOpen, update])\n\n // enter transition + reposition listeners while open\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => setVisible(true))\n\n const onReposition = () => update()\n window.addEventListener('resize', onReposition)\n window.addEventListener('scroll', onReposition, true)\n let ro: ResizeObserver | undefined\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(onReposition)\n if (panelRef.current) ro.observe(panelRef.current)\n if (triggerRef.current) ro.observe(triggerRef.current)\n }\n\n return () => {\n cancelAnimationFrame(raf)\n window.removeEventListener('resize', onReposition)\n window.removeEventListener('scroll', onReposition, true)\n ro?.disconnect()\n }\n }, [isOpen, update])\n\n // outside click + keyboard (Escape, arrow roving)\n useEffect(() => {\n if (!isOpen) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target as Node\n if (triggerRef.current?.contains(target) || panelRef.current?.contains(target)) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n close()\n triggerRef.current?.focus()\n } else if (event.key === 'Tab') {\n // Tab would move focus by portal DOM order (end of <body>), orphaning the open menu — close it\n // and let focus continue naturally from the trigger (Select/MultiSelect do the same)\n close()\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n const items = focusableItems(panelRef.current)\n if (!items.length) return\n const current = items.indexOf(document.activeElement as HTMLElement)\n const delta = event.key === 'ArrowDown' ? 1 : -1\n const next = (current + delta + items.length) % items.length\n items[next]?.focus()\n }\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [isOpen, close])\n\n // focus the first item once the menu is open and positioned\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => focusableItems(panelRef.current)[0]?.focus())\n return () => cancelAnimationFrame(raf)\n }, [isOpen])\n\n const triggerProps = trigger.props as {\n onClick?: (event: ReactMouseEvent) => void\n ref?: Ref<HTMLElement>\n }\n const originalRef = triggerProps.ref\n\n const clonedTrigger = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef) (originalRef as { current: HTMLElement | null }).current = node\n },\n onClick: (event: ReactMouseEvent) => {\n triggerProps.onClick?.(event)\n if (!disabled) setOpen(!isOpen)\n },\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? menuId : undefined,\n })\n\n const handlePanelClick = (event: ReactMouseEvent) => {\n if (!closeOnSelect) return\n const item = (event.target as HTMLElement).closest(FOCUSABLE)\n if (item && item.getAttribute('aria-disabled') !== 'true') {\n close()\n triggerRef.current?.focus()\n }\n }\n\n return (\n <>\n {clonedTrigger}\n {isOpen &&\n createPortal(\n <div\n ref={panelRef}\n id={menuId}\n className={clsx(styles.panel, minWidth && styles[size], className)}\n data-open={visible ? 'true' : 'false'}\n data-side={pos?.side ?? 'bottom'}\n style={{\n position: 'fixed',\n top: pos?.top ?? 0,\n left: pos?.left ?? 0,\n maxHeight: pos?.maxHeight,\n minWidth: pos?.minWidth,\n visibility: pos ? 'visible' : 'hidden',\n ...style,\n }}\n onClick={handlePanelClick}\n >\n <List role=\"menu\" size={size} padding=\"xs\">\n {children}\n </List>\n </div>,\n document.body,\n )}\n </>\n )\n}\n"],"names":["VIEWPORT_PADDING","FOCUSABLE","focusableItems","panel","el","Dropdown","trigger","children","placement","size","minWidth","open","defaultOpen","onOpenChange","closeOnSelect","matchTriggerWidth","disabled","offset","className","style","menuId","useId","triggerRef","useRef","panelRef","isControlled","internalOpen","setInternalOpen","useState","isOpen","visible","setVisible","pos","setPos","setOpen","useCallback","next","close","useLockBodyScroll","update","triggerEl","rect","panelW","panelH","vw","vh","pad","spaceBelow","spaceAbove","side","maxHeight","usedH","top","left","useLayoutEffect","useEffect","raf","onReposition","ro","onPointerDown","event","target","_a","_b","onKeyDown","items","current","delta","triggerProps","originalRef","clonedTrigger","cloneElement","node","handlePanelClick","item","jsxs","Fragment","createPortal","jsx","clsx","styles","List"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown-CMqWq6J_.cjs","sources":["../src/components/Dropdown/Dropdown.tsx"],"sourcesContent":["import {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { List, type ListItemSize } from '../List'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Dropdown.module.css'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface Position {\n top: number\n left: number\n side: 'top' | 'bottom'\n maxHeight: number\n minWidth?: number\n}\n\nexport interface DropdownProps {\n /** The element that opens the menu (e.g. a `Button` / `IconButton`). Cloned to wire click + a11y. */\n trigger: ReactElement\n /** Menu content — typically `ListItem`s (composed inside a `role=\"menu\"` `List`). */\n children: ReactNode\n /** Preferred placement. Flips to the opposite side automatically when it would overflow. Default `bottom-start`. */\n placement?: DropdownPlacement\n /** Menu size — sets the panel min-width (`sm` 150 · `md` 190 · `lg` 220) and the items' density. Default `md`. */\n size?: ListItemSize\n /**\n * Apply the size-based min-width (`sm` 150 · `md` 190 · `lg` 220px). Defaults to `true`; set `false`\n * to let the menu size to its content instead (the items' density still tracks `size`).\n */\n minWidth?: boolean\n /** Controlled open state. */\n open?: boolean\n /** Initial open state for uncontrolled use. Defaults to `false`. */\n defaultOpen?: boolean\n /** Fires with the next open state. */\n onOpenChange?: (open: boolean) => void\n /** Close the menu when an item inside is clicked. Defaults to `true`. */\n closeOnSelect?: boolean\n /** Make the menu at least as wide as the trigger (select-like). Defaults to `false`. */\n matchTriggerWidth?: boolean\n /** Prevents opening. */\n disabled?: boolean\n /** Gap between the trigger and the menu, in px. Defaults to `6`. */\n offset?: number\n /** Class applied to the floating panel. */\n className?: string\n /** Style applied to the floating panel. */\n style?: CSSProperties\n}\n\n/** Distance the menu is kept from the viewport edges (px). */\nconst VIEWPORT_PADDING = 8\n/** Focusable menu items, used for arrow-key roving. */\nconst FOCUSABLE =\n '[role=\"menuitem\"],[role=\"button\"],a[href],button:not([disabled]),[tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableItems(panel: HTMLElement | null): HTMLElement[] {\n if (!panel) return []\n return Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.getAttribute('aria-disabled') !== 'true' && el.offsetParent !== null,\n )\n}\n\n/**\n * A floating menu anchored to a `trigger`. Opens on trigger click; closes on outside click, `Escape`,\n * or selecting an item. The panel is portaled to `document.body` and positioned with collision\n * handling — it **flips** to the opposite side when it would overflow, clamps within the viewport, and\n * re-positions on scroll/resize (a too-tall menu caps its height and scrolls). Arrow keys move between\n * items; `Escape` returns focus to the trigger. Compose `ListItem`s as `children`.\n */\nexport function Dropdown({\n trigger,\n children,\n placement = 'bottom-start',\n size = 'md',\n minWidth = true,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnSelect = true,\n matchTriggerWidth = false,\n disabled = false,\n offset = 6,\n className,\n style,\n}: DropdownProps) {\n const menuId = useId()\n const triggerRef = useRef<HTMLElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n const isControlled = open !== undefined\n const [internalOpen, setInternalOpen] = useState(defaultOpen)\n const isOpen = isControlled ? open : internalOpen\n const [visible, setVisible] = useState(false)\n const [pos, setPos] = useState<Position | null>(null)\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n const close = useCallback(() => setOpen(false), [setOpen])\n\n // lock page scroll while the menu is open (no scrollbar shift)\n useLockBodyScroll(isOpen)\n\n // ── positioning: flip when it would overflow, clamp inside the viewport ──\n const update = useCallback(() => {\n const triggerEl = triggerRef.current\n const panel = panelRef.current\n if (!triggerEl || !panel) return\n\n const rect = triggerEl.getBoundingClientRect()\n const panelW = panel.offsetWidth\n const panelH = panel.offsetHeight\n const vw = window.innerWidth\n const vh = window.innerHeight\n const pad = VIEWPORT_PADDING\n\n const spaceBelow = vh - rect.bottom - offset - pad\n const spaceAbove = rect.top - offset - pad\n let side: 'top' | 'bottom' = placement.startsWith('bottom') ? 'bottom' : 'top'\n // flip only when the preferred side can't fit AND the opposite side has more room\n if (side === 'bottom' && panelH > spaceBelow && spaceAbove > spaceBelow) side = 'top'\n else if (side === 'top' && panelH > spaceAbove && spaceBelow > spaceAbove) side = 'bottom'\n\n const available = side === 'bottom' ? spaceBelow : spaceAbove\n const maxHeight = Math.max(0, available)\n const usedH = Math.min(panelH, maxHeight)\n\n let top = side === 'bottom' ? rect.bottom + offset : rect.top - offset - usedH\n top = Math.min(Math.max(top, pad), Math.max(pad, vh - pad - usedH))\n\n let left = placement.endsWith('end') ? rect.right - panelW : rect.left\n left = Math.min(Math.max(left, pad), Math.max(pad, vw - pad - panelW))\n\n setPos({ top, left, side, maxHeight, minWidth: matchTriggerWidth ? rect.width : undefined })\n }, [placement, offset, matchTriggerWidth])\n\n // position synchronously before paint whenever the menu is open\n useLayoutEffect(() => {\n if (!isOpen) {\n setVisible(false)\n return\n }\n update()\n }, [isOpen, update])\n\n // enter transition + reposition listeners while open\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => setVisible(true))\n\n const onReposition = () => update()\n window.addEventListener('resize', onReposition)\n window.addEventListener('scroll', onReposition, true)\n let ro: ResizeObserver | undefined\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(onReposition)\n if (panelRef.current) ro.observe(panelRef.current)\n if (triggerRef.current) ro.observe(triggerRef.current)\n }\n\n return () => {\n cancelAnimationFrame(raf)\n window.removeEventListener('resize', onReposition)\n window.removeEventListener('scroll', onReposition, true)\n ro?.disconnect()\n }\n }, [isOpen, update])\n\n // outside click + keyboard (Escape, arrow roving)\n useEffect(() => {\n if (!isOpen) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target as Node\n if (triggerRef.current?.contains(target) || panelRef.current?.contains(target)) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n close()\n triggerRef.current?.focus()\n } else if (event.key === 'Tab') {\n // Tab would move focus by portal DOM order (end of <body>), orphaning the open menu — close it\n // and let focus continue naturally from the trigger (Select/MultiSelect do the same)\n close()\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n const items = focusableItems(panelRef.current)\n if (!items.length) return\n const current = items.indexOf(document.activeElement as HTMLElement)\n const delta = event.key === 'ArrowDown' ? 1 : -1\n const next = (current + delta + items.length) % items.length\n items[next]?.focus()\n }\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [isOpen, close])\n\n // focus the first item once the menu is open and positioned\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => focusableItems(panelRef.current)[0]?.focus())\n return () => cancelAnimationFrame(raf)\n }, [isOpen])\n\n const triggerProps = trigger.props as {\n onClick?: (event: ReactMouseEvent) => void\n ref?: Ref<HTMLElement>\n }\n const originalRef = triggerProps.ref\n\n const clonedTrigger = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef) (originalRef as { current: HTMLElement | null }).current = node\n },\n onClick: (event: ReactMouseEvent) => {\n triggerProps.onClick?.(event)\n if (!disabled) setOpen(!isOpen)\n },\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? menuId : undefined,\n })\n\n const handlePanelClick = (event: ReactMouseEvent) => {\n if (!closeOnSelect) return\n const item = (event.target as HTMLElement).closest(FOCUSABLE)\n if (item && item.getAttribute('aria-disabled') !== 'true') {\n close()\n triggerRef.current?.focus()\n }\n }\n\n return (\n <>\n {clonedTrigger}\n {isOpen &&\n createPortal(\n <div\n ref={panelRef}\n id={menuId}\n className={clsx(styles.panel, minWidth && styles[size], className)}\n data-open={visible ? 'true' : 'false'}\n data-side={pos?.side ?? 'bottom'}\n style={{\n position: 'fixed',\n top: pos?.top ?? 0,\n left: pos?.left ?? 0,\n maxHeight: pos?.maxHeight,\n minWidth: pos?.minWidth,\n visibility: pos ? 'visible' : 'hidden',\n ...style,\n }}\n onClick={handlePanelClick}\n >\n <List role=\"menu\" size={size} padding=\"xs\">\n {children}\n </List>\n </div>,\n document.body,\n )}\n </>\n )\n}\n"],"names":["VIEWPORT_PADDING","FOCUSABLE","focusableItems","panel","el","Dropdown","trigger","children","placement","size","minWidth","open","defaultOpen","onOpenChange","closeOnSelect","matchTriggerWidth","disabled","offset","className","style","menuId","useId","triggerRef","useRef","panelRef","isControlled","internalOpen","setInternalOpen","useState","isOpen","visible","setVisible","pos","setPos","setOpen","useCallback","next","close","useLockBodyScroll","update","triggerEl","rect","panelW","panelH","vw","vh","pad","spaceBelow","spaceAbove","side","maxHeight","usedH","top","left","useLayoutEffect","useEffect","raf","onReposition","ro","onPointerDown","event","target","_a","_b","onKeyDown","items","current","delta","triggerProps","originalRef","clonedTrigger","cloneElement","node","handlePanelClick","item","jsxs","Fragment","createPortal","jsx","clsx","styles","List"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsxs as et, Fragment as nt, jsx as q } from "react/jsx-runtime";
|
|
|
2
2
|
import { useId as ot, useRef as z, useState as R, useCallback as M, useLayoutEffect as rt, useEffect as W, cloneElement as it } from "react";
|
|
3
3
|
import { createPortal as st } from "react-dom";
|
|
4
4
|
import { clsx as ct } from "clsx";
|
|
5
|
-
import { L as at } from "./List-
|
|
5
|
+
import { L as at } from "./List-CXHlAI5w.js";
|
|
6
6
|
import { u as lt } from "./useLockBodyScroll-DwBILLPK.js";
|
|
7
7
|
const ut = "_panel_ntp6g_4", dt = "_sm_ntp6g_21", mt = "_md_ntp6g_24", ft = "_lg_ntp6g_27", C = {
|
|
8
8
|
panel: ut,
|
|
@@ -143,4 +143,4 @@ function Et({
|
|
|
143
143
|
export {
|
|
144
144
|
Et as D
|
|
145
145
|
};
|
|
146
|
-
//# sourceMappingURL=Dropdown-
|
|
146
|
+
//# sourceMappingURL=Dropdown-zlv96RLy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown-BlmbYp1X.js","sources":["../src/components/Dropdown/Dropdown.tsx"],"sourcesContent":["import {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { List, type ListItemSize } from '../List'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Dropdown.module.css'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface Position {\n top: number\n left: number\n side: 'top' | 'bottom'\n maxHeight: number\n minWidth?: number\n}\n\nexport interface DropdownProps {\n /** The element that opens the menu (e.g. a `Button` / `IconButton`). Cloned to wire click + a11y. */\n trigger: ReactElement\n /** Menu content — typically `ListItem`s (composed inside a `role=\"menu\"` `List`). */\n children: ReactNode\n /** Preferred placement. Flips to the opposite side automatically when it would overflow. Default `bottom-start`. */\n placement?: DropdownPlacement\n /** Menu size — sets the panel min-width (`sm` 150 · `md` 190 · `lg` 220) and the items' density. Default `md`. */\n size?: ListItemSize\n /**\n * Apply the size-based min-width (`sm` 150 · `md` 190 · `lg` 220px). Defaults to `true`; set `false`\n * to let the menu size to its content instead (the items' density still tracks `size`).\n */\n minWidth?: boolean\n /** Controlled open state. */\n open?: boolean\n /** Initial open state for uncontrolled use. Defaults to `false`. */\n defaultOpen?: boolean\n /** Fires with the next open state. */\n onOpenChange?: (open: boolean) => void\n /** Close the menu when an item inside is clicked. Defaults to `true`. */\n closeOnSelect?: boolean\n /** Make the menu at least as wide as the trigger (select-like). Defaults to `false`. */\n matchTriggerWidth?: boolean\n /** Prevents opening. */\n disabled?: boolean\n /** Gap between the trigger and the menu, in px. Defaults to `6`. */\n offset?: number\n /** Class applied to the floating panel. */\n className?: string\n /** Style applied to the floating panel. */\n style?: CSSProperties\n}\n\n/** Distance the menu is kept from the viewport edges (px). */\nconst VIEWPORT_PADDING = 8\n/** Focusable menu items, used for arrow-key roving. */\nconst FOCUSABLE =\n '[role=\"menuitem\"],[role=\"button\"],a[href],button:not([disabled]),[tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableItems(panel: HTMLElement | null): HTMLElement[] {\n if (!panel) return []\n return Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.getAttribute('aria-disabled') !== 'true' && el.offsetParent !== null,\n )\n}\n\n/**\n * A floating menu anchored to a `trigger`. Opens on trigger click; closes on outside click, `Escape`,\n * or selecting an item. The panel is portaled to `document.body` and positioned with collision\n * handling — it **flips** to the opposite side when it would overflow, clamps within the viewport, and\n * re-positions on scroll/resize (a too-tall menu caps its height and scrolls). Arrow keys move between\n * items; `Escape` returns focus to the trigger. Compose `ListItem`s as `children`.\n */\nexport function Dropdown({\n trigger,\n children,\n placement = 'bottom-start',\n size = 'md',\n minWidth = true,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnSelect = true,\n matchTriggerWidth = false,\n disabled = false,\n offset = 6,\n className,\n style,\n}: DropdownProps) {\n const menuId = useId()\n const triggerRef = useRef<HTMLElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n const isControlled = open !== undefined\n const [internalOpen, setInternalOpen] = useState(defaultOpen)\n const isOpen = isControlled ? open : internalOpen\n const [visible, setVisible] = useState(false)\n const [pos, setPos] = useState<Position | null>(null)\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n const close = useCallback(() => setOpen(false), [setOpen])\n\n // lock page scroll while the menu is open (no scrollbar shift)\n useLockBodyScroll(isOpen)\n\n // ── positioning: flip when it would overflow, clamp inside the viewport ──\n const update = useCallback(() => {\n const triggerEl = triggerRef.current\n const panel = panelRef.current\n if (!triggerEl || !panel) return\n\n const rect = triggerEl.getBoundingClientRect()\n const panelW = panel.offsetWidth\n const panelH = panel.offsetHeight\n const vw = window.innerWidth\n const vh = window.innerHeight\n const pad = VIEWPORT_PADDING\n\n const spaceBelow = vh - rect.bottom - offset - pad\n const spaceAbove = rect.top - offset - pad\n let side: 'top' | 'bottom' = placement.startsWith('bottom') ? 'bottom' : 'top'\n // flip only when the preferred side can't fit AND the opposite side has more room\n if (side === 'bottom' && panelH > spaceBelow && spaceAbove > spaceBelow) side = 'top'\n else if (side === 'top' && panelH > spaceAbove && spaceBelow > spaceAbove) side = 'bottom'\n\n const available = side === 'bottom' ? spaceBelow : spaceAbove\n const maxHeight = Math.max(0, available)\n const usedH = Math.min(panelH, maxHeight)\n\n let top = side === 'bottom' ? rect.bottom + offset : rect.top - offset - usedH\n top = Math.min(Math.max(top, pad), Math.max(pad, vh - pad - usedH))\n\n let left = placement.endsWith('end') ? rect.right - panelW : rect.left\n left = Math.min(Math.max(left, pad), Math.max(pad, vw - pad - panelW))\n\n setPos({ top, left, side, maxHeight, minWidth: matchTriggerWidth ? rect.width : undefined })\n }, [placement, offset, matchTriggerWidth])\n\n // position synchronously before paint whenever the menu is open\n useLayoutEffect(() => {\n if (!isOpen) {\n setVisible(false)\n return\n }\n update()\n }, [isOpen, update])\n\n // enter transition + reposition listeners while open\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => setVisible(true))\n\n const onReposition = () => update()\n window.addEventListener('resize', onReposition)\n window.addEventListener('scroll', onReposition, true)\n let ro: ResizeObserver | undefined\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(onReposition)\n if (panelRef.current) ro.observe(panelRef.current)\n if (triggerRef.current) ro.observe(triggerRef.current)\n }\n\n return () => {\n cancelAnimationFrame(raf)\n window.removeEventListener('resize', onReposition)\n window.removeEventListener('scroll', onReposition, true)\n ro?.disconnect()\n }\n }, [isOpen, update])\n\n // outside click + keyboard (Escape, arrow roving)\n useEffect(() => {\n if (!isOpen) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target as Node\n if (triggerRef.current?.contains(target) || panelRef.current?.contains(target)) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n close()\n triggerRef.current?.focus()\n } else if (event.key === 'Tab') {\n // Tab would move focus by portal DOM order (end of <body>), orphaning the open menu — close it\n // and let focus continue naturally from the trigger (Select/MultiSelect do the same)\n close()\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n const items = focusableItems(panelRef.current)\n if (!items.length) return\n const current = items.indexOf(document.activeElement as HTMLElement)\n const delta = event.key === 'ArrowDown' ? 1 : -1\n const next = (current + delta + items.length) % items.length\n items[next]?.focus()\n }\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [isOpen, close])\n\n // focus the first item once the menu is open and positioned\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => focusableItems(panelRef.current)[0]?.focus())\n return () => cancelAnimationFrame(raf)\n }, [isOpen])\n\n const triggerProps = trigger.props as {\n onClick?: (event: ReactMouseEvent) => void\n ref?: Ref<HTMLElement>\n }\n const originalRef = triggerProps.ref\n\n const clonedTrigger = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef) (originalRef as { current: HTMLElement | null }).current = node\n },\n onClick: (event: ReactMouseEvent) => {\n triggerProps.onClick?.(event)\n if (!disabled) setOpen(!isOpen)\n },\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? menuId : undefined,\n })\n\n const handlePanelClick = (event: ReactMouseEvent) => {\n if (!closeOnSelect) return\n const item = (event.target as HTMLElement).closest(FOCUSABLE)\n if (item && item.getAttribute('aria-disabled') !== 'true') {\n close()\n triggerRef.current?.focus()\n }\n }\n\n return (\n <>\n {clonedTrigger}\n {isOpen &&\n createPortal(\n <div\n ref={panelRef}\n id={menuId}\n className={clsx(styles.panel, minWidth && styles[size], className)}\n data-open={visible ? 'true' : 'false'}\n data-side={pos?.side ?? 'bottom'}\n style={{\n position: 'fixed',\n top: pos?.top ?? 0,\n left: pos?.left ?? 0,\n maxHeight: pos?.maxHeight,\n minWidth: pos?.minWidth,\n visibility: pos ? 'visible' : 'hidden',\n ...style,\n }}\n onClick={handlePanelClick}\n >\n <List role=\"menu\" size={size} padding=\"xs\">\n {children}\n </List>\n </div>,\n document.body,\n )}\n </>\n )\n}\n"],"names":["VIEWPORT_PADDING","FOCUSABLE","focusableItems","panel","el","Dropdown","trigger","children","placement","size","minWidth","open","defaultOpen","onOpenChange","closeOnSelect","matchTriggerWidth","disabled","offset","className","style","menuId","useId","triggerRef","useRef","panelRef","isControlled","internalOpen","setInternalOpen","useState","isOpen","visible","setVisible","pos","setPos","setOpen","useCallback","next","close","useLockBodyScroll","update","triggerEl","rect","panelW","panelH","vw","vh","pad","spaceBelow","spaceAbove","side","maxHeight","usedH","top","left","useLayoutEffect","useEffect","raf","onReposition","ro","onPointerDown","event","target","_a","_b","onKeyDown","items","current","delta","triggerProps","originalRef","clonedTrigger","cloneElement","node","handlePanelClick","item","jsxs","Fragment","createPortal","jsx","clsx","styles","List"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown-zlv96RLy.js","sources":["../src/components/Dropdown/Dropdown.tsx"],"sourcesContent":["import {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { List, type ListItemSize } from '../List'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Dropdown.module.css'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface Position {\n top: number\n left: number\n side: 'top' | 'bottom'\n maxHeight: number\n minWidth?: number\n}\n\nexport interface DropdownProps {\n /** The element that opens the menu (e.g. a `Button` / `IconButton`). Cloned to wire click + a11y. */\n trigger: ReactElement\n /** Menu content — typically `ListItem`s (composed inside a `role=\"menu\"` `List`). */\n children: ReactNode\n /** Preferred placement. Flips to the opposite side automatically when it would overflow. Default `bottom-start`. */\n placement?: DropdownPlacement\n /** Menu size — sets the panel min-width (`sm` 150 · `md` 190 · `lg` 220) and the items' density. Default `md`. */\n size?: ListItemSize\n /**\n * Apply the size-based min-width (`sm` 150 · `md` 190 · `lg` 220px). Defaults to `true`; set `false`\n * to let the menu size to its content instead (the items' density still tracks `size`).\n */\n minWidth?: boolean\n /** Controlled open state. */\n open?: boolean\n /** Initial open state for uncontrolled use. Defaults to `false`. */\n defaultOpen?: boolean\n /** Fires with the next open state. */\n onOpenChange?: (open: boolean) => void\n /** Close the menu when an item inside is clicked. Defaults to `true`. */\n closeOnSelect?: boolean\n /** Make the menu at least as wide as the trigger (select-like). Defaults to `false`. */\n matchTriggerWidth?: boolean\n /** Prevents opening. */\n disabled?: boolean\n /** Gap between the trigger and the menu, in px. Defaults to `6`. */\n offset?: number\n /** Class applied to the floating panel. */\n className?: string\n /** Style applied to the floating panel. */\n style?: CSSProperties\n}\n\n/** Distance the menu is kept from the viewport edges (px). */\nconst VIEWPORT_PADDING = 8\n/** Focusable menu items, used for arrow-key roving. */\nconst FOCUSABLE =\n '[role=\"menuitem\"],[role=\"button\"],a[href],button:not([disabled]),[tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableItems(panel: HTMLElement | null): HTMLElement[] {\n if (!panel) return []\n return Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.getAttribute('aria-disabled') !== 'true' && el.offsetParent !== null,\n )\n}\n\n/**\n * A floating menu anchored to a `trigger`. Opens on trigger click; closes on outside click, `Escape`,\n * or selecting an item. The panel is portaled to `document.body` and positioned with collision\n * handling — it **flips** to the opposite side when it would overflow, clamps within the viewport, and\n * re-positions on scroll/resize (a too-tall menu caps its height and scrolls). Arrow keys move between\n * items; `Escape` returns focus to the trigger. Compose `ListItem`s as `children`.\n */\nexport function Dropdown({\n trigger,\n children,\n placement = 'bottom-start',\n size = 'md',\n minWidth = true,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnSelect = true,\n matchTriggerWidth = false,\n disabled = false,\n offset = 6,\n className,\n style,\n}: DropdownProps) {\n const menuId = useId()\n const triggerRef = useRef<HTMLElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n\n const isControlled = open !== undefined\n const [internalOpen, setInternalOpen] = useState(defaultOpen)\n const isOpen = isControlled ? open : internalOpen\n const [visible, setVisible] = useState(false)\n const [pos, setPos] = useState<Position | null>(null)\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n const close = useCallback(() => setOpen(false), [setOpen])\n\n // lock page scroll while the menu is open (no scrollbar shift)\n useLockBodyScroll(isOpen)\n\n // ── positioning: flip when it would overflow, clamp inside the viewport ──\n const update = useCallback(() => {\n const triggerEl = triggerRef.current\n const panel = panelRef.current\n if (!triggerEl || !panel) return\n\n const rect = triggerEl.getBoundingClientRect()\n const panelW = panel.offsetWidth\n const panelH = panel.offsetHeight\n const vw = window.innerWidth\n const vh = window.innerHeight\n const pad = VIEWPORT_PADDING\n\n const spaceBelow = vh - rect.bottom - offset - pad\n const spaceAbove = rect.top - offset - pad\n let side: 'top' | 'bottom' = placement.startsWith('bottom') ? 'bottom' : 'top'\n // flip only when the preferred side can't fit AND the opposite side has more room\n if (side === 'bottom' && panelH > spaceBelow && spaceAbove > spaceBelow) side = 'top'\n else if (side === 'top' && panelH > spaceAbove && spaceBelow > spaceAbove) side = 'bottom'\n\n const available = side === 'bottom' ? spaceBelow : spaceAbove\n const maxHeight = Math.max(0, available)\n const usedH = Math.min(panelH, maxHeight)\n\n let top = side === 'bottom' ? rect.bottom + offset : rect.top - offset - usedH\n top = Math.min(Math.max(top, pad), Math.max(pad, vh - pad - usedH))\n\n let left = placement.endsWith('end') ? rect.right - panelW : rect.left\n left = Math.min(Math.max(left, pad), Math.max(pad, vw - pad - panelW))\n\n setPos({ top, left, side, maxHeight, minWidth: matchTriggerWidth ? rect.width : undefined })\n }, [placement, offset, matchTriggerWidth])\n\n // position synchronously before paint whenever the menu is open\n useLayoutEffect(() => {\n if (!isOpen) {\n setVisible(false)\n return\n }\n update()\n }, [isOpen, update])\n\n // enter transition + reposition listeners while open\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => setVisible(true))\n\n const onReposition = () => update()\n window.addEventListener('resize', onReposition)\n window.addEventListener('scroll', onReposition, true)\n let ro: ResizeObserver | undefined\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(onReposition)\n if (panelRef.current) ro.observe(panelRef.current)\n if (triggerRef.current) ro.observe(triggerRef.current)\n }\n\n return () => {\n cancelAnimationFrame(raf)\n window.removeEventListener('resize', onReposition)\n window.removeEventListener('scroll', onReposition, true)\n ro?.disconnect()\n }\n }, [isOpen, update])\n\n // outside click + keyboard (Escape, arrow roving)\n useEffect(() => {\n if (!isOpen) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target as Node\n if (triggerRef.current?.contains(target) || panelRef.current?.contains(target)) return\n close()\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n close()\n triggerRef.current?.focus()\n } else if (event.key === 'Tab') {\n // Tab would move focus by portal DOM order (end of <body>), orphaning the open menu — close it\n // and let focus continue naturally from the trigger (Select/MultiSelect do the same)\n close()\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n const items = focusableItems(panelRef.current)\n if (!items.length) return\n const current = items.indexOf(document.activeElement as HTMLElement)\n const delta = event.key === 'ArrowDown' ? 1 : -1\n const next = (current + delta + items.length) % items.length\n items[next]?.focus()\n }\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [isOpen, close])\n\n // focus the first item once the menu is open and positioned\n useEffect(() => {\n if (!isOpen) return\n const raf = requestAnimationFrame(() => focusableItems(panelRef.current)[0]?.focus())\n return () => cancelAnimationFrame(raf)\n }, [isOpen])\n\n const triggerProps = trigger.props as {\n onClick?: (event: ReactMouseEvent) => void\n ref?: Ref<HTMLElement>\n }\n const originalRef = triggerProps.ref\n\n const clonedTrigger = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef) (originalRef as { current: HTMLElement | null }).current = node\n },\n onClick: (event: ReactMouseEvent) => {\n triggerProps.onClick?.(event)\n if (!disabled) setOpen(!isOpen)\n },\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? menuId : undefined,\n })\n\n const handlePanelClick = (event: ReactMouseEvent) => {\n if (!closeOnSelect) return\n const item = (event.target as HTMLElement).closest(FOCUSABLE)\n if (item && item.getAttribute('aria-disabled') !== 'true') {\n close()\n triggerRef.current?.focus()\n }\n }\n\n return (\n <>\n {clonedTrigger}\n {isOpen &&\n createPortal(\n <div\n ref={panelRef}\n id={menuId}\n className={clsx(styles.panel, minWidth && styles[size], className)}\n data-open={visible ? 'true' : 'false'}\n data-side={pos?.side ?? 'bottom'}\n style={{\n position: 'fixed',\n top: pos?.top ?? 0,\n left: pos?.left ?? 0,\n maxHeight: pos?.maxHeight,\n minWidth: pos?.minWidth,\n visibility: pos ? 'visible' : 'hidden',\n ...style,\n }}\n onClick={handlePanelClick}\n >\n <List role=\"menu\" size={size} padding=\"xs\">\n {children}\n </List>\n </div>,\n document.body,\n )}\n </>\n )\n}\n"],"names":["VIEWPORT_PADDING","FOCUSABLE","focusableItems","panel","el","Dropdown","trigger","children","placement","size","minWidth","open","defaultOpen","onOpenChange","closeOnSelect","matchTriggerWidth","disabled","offset","className","style","menuId","useId","triggerRef","useRef","panelRef","isControlled","internalOpen","setInternalOpen","useState","isOpen","visible","setVisible","pos","setPos","setOpen","useCallback","next","close","useLockBodyScroll","update","triggerEl","rect","panelW","panelH","vw","vh","pad","spaceBelow","spaceAbove","side","maxHeight","usedH","top","left","useLayoutEffect","useEffect","raf","onReposition","ro","onPointerDown","event","target","_a","_b","onKeyDown","items","current","delta","triggerProps","originalRef","clonedTrigger","cloneElement","node","handlePanelClick","item","jsxs","Fragment","createPortal","jsx","clsx","styles","List"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { forwardRef as S } from "react";
|
|
|
3
3
|
import { clsx as N } from "clsx";
|
|
4
4
|
import { I as c } from "./Icon-CGQ5yGSZ.js";
|
|
5
5
|
import { a as h } from "./names-BR1uJs0-.js";
|
|
6
|
-
import { a as g } from "./ConfigProvider-
|
|
6
|
+
import { a as g } from "./ConfigProvider-D2svpXFu.js";
|
|
7
7
|
const E = "_emptyState_1vpxy_3", I = "_sm_1vpxy_17", b = "_md_1vpxy_23", O = "_lg_1vpxy_29", T = "_icon_1vpxy_37", j = "_title_1vpxy_55", w = "_description_1vpxy_61", z = "_action_1vpxy_70", A = "_pattern_1vpxy_77", C = "_tinted_1vpxy_100", t = {
|
|
8
8
|
emptyState: E,
|
|
9
9
|
sm: I,
|
|
@@ -55,4 +55,4 @@ const E = "_emptyState_1vpxy_3", I = "_sm_1vpxy_17", b = "_md_1vpxy_23", O = "_l
|
|
|
55
55
|
export {
|
|
56
56
|
G as E
|
|
57
57
|
};
|
|
58
|
-
//# sourceMappingURL=EmptyState-
|
|
58
|
+
//# sourceMappingURL=EmptyState-CvpKSYY4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState-
|
|
1
|
+
{"version":3,"file":"EmptyState-CvpKSYY4.js","sources":["../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import { forwardRef, type CSSProperties, type HTMLAttributes, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport styles from './EmptyState.module.css'\n\nexport type EmptyStateSize = 'sm' | 'md' | 'lg'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\nexport interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'color'> {\n /** Leading glyph shown in a soft circle — an `IconName`, any node, or `false` to hide it. Defaults to `FolderOpen`. */\n icon?: IconName | ReactNode | false\n /** Heading line. Defaults to `\"No Results Found\"`. */\n title?: ReactNode\n /** Muted description under the title (e.g. a hint on what to do next). */\n description?: ReactNode\n /** Action slot under the text — e.g. an \"Add Item\" or \"Clear Filters\" button. */\n action?: ReactNode\n /** Size — scales the icon, text, and vertical padding. Defaults to `md`. */\n size?: EmptyStateSize\n /**\n * Polished \"hero\" look: a faded grid backdrop (fades out toward the edges) + an elevated icon\n * (gradient + drop shadow). Defaults to `true`; pass `pattern={false}` for the flat, compact placeholder.\n */\n pattern?: boolean\n /** Tint the icon puck with a theme color (e.g. `error` for a failure). Omitted → the neutral muted puck. */\n color?: ThemeColor\n /** Extra content rendered below the action. */\n children?: ReactNode\n}\n\n/**\n * The empty-state placeholder — drop it in wherever a page, table, list, or gallery has nothing to\n * show (no records yet, no search matches). A centered, muted glyph in a soft circle + a `title` +\n * an optional `description` and `action` (e.g. a \"Add Item\" / \"Clear Filters\" button). Neutral by\n * design; pass a custom `icon` node for a tinted glyph. Token-only styling.\n */\nexport const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(function EmptyState(\n {\n icon,\n title,\n description,\n action,\n size = 'md',\n pattern = true,\n color,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const t = useT()\n const resolvedTitle = title ?? t('emptyState.title')\n const renderedIcon =\n icon === false ? null : icon == null ? (\n <Icon name=\"FolderOpen\" />\n ) : typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} />\n ) : (\n icon\n )\n\n return (\n <div\n ref={ref}\n className={clsx(\n styles.emptyState,\n styles[size],\n pattern && styles.pattern,\n color && styles.tinted,\n className,\n )}\n style={\n (color\n ? { '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`, ...style }\n : style) as CSSProperties\n }\n {...props}\n >\n {renderedIcon != null && (\n <div className={styles.icon} aria-hidden>\n {renderedIcon}\n </div>\n )}\n {resolvedTitle != null && <div className={styles.title}>{resolvedTitle}</div>}\n {description != null && <div className={styles.description}>{description}</div>}\n {action != null && <div className={styles.action}>{action}</div>}\n {children}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","EmptyState","forwardRef","icon","title","description","action","size","pattern","color","className","style","children","props","ref","t","useT","resolvedTitle","renderedIcon","jsx","Icon","jsxs","clsx","styles"],"mappings":";;;;;;;;;;;;;;;;;GASMA,IAAgB,IAAI,IAAYC,CAAU,GA8BnCC,IAAaC,EAA4C,SACpE;AAAA,EACE,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,QAAMC,IAAIC,EAAA,GACJC,IAAgBb,KAASW,EAAE,kBAAkB,GAC7CG,IACJf,MAAS,KAAQ,OAAOA,KAAQ,OAC9B,gBAAAgB,EAACC,GAAA,EAAK,MAAK,aAAA,CAAa,IACtB,OAAOjB,KAAS,YAAYJ,EAAc,IAAII,CAAI,IACpD,gBAAAgB,EAACC,GAAA,EAAK,MAAMjB,EAAA,CAAkB,IAE9BA;AAGJ,SACE,gBAAAkB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAP;AAAA,MACA,WAAWQ;AAAA,QACTC,EAAO;AAAA,QACPA,EAAOhB,CAAI;AAAA,QACXC,KAAWe,EAAO;AAAA,QAClBd,KAASc,EAAO;AAAA,QAChBb;AAAA,MAAA;AAAA,MAEF,OACGD,IACG,EAAE,gBAAgB,kBAAkBA,CAAK,SAAS,GAAGE,EAAA,IACrDA;AAAA,MAEL,GAAGE;AAAA,MAEH,UAAA;AAAA,QAAAK,KAAgB,0BACd,OAAA,EAAI,WAAWK,EAAO,MAAM,eAAW,IACrC,UAAAL,EAAA,CACH;AAAA,QAEDD,KAAiB,QAAQ,gBAAAE,EAAC,SAAI,WAAWI,EAAO,OAAQ,UAAAN,GAAc;AAAA,QACtEZ,KAAe,QAAQ,gBAAAc,EAAC,SAAI,WAAWI,EAAO,aAAc,UAAAlB,GAAY;AAAA,QACxEC,KAAU,QAAQ,gBAAAa,EAAC,SAAI,WAAWI,EAAO,QAAS,UAAAjB,GAAO;AAAA,QACzDM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e=require("react/jsx-runtime"),S=require("react"),N=require("clsx"),a=require("./Icon-BUP5_kRs.cjs"),j=require("./names-YOCJ4B5J.cjs"),g=require("./ConfigProvider-
|
|
2
|
-
//# sourceMappingURL=EmptyState-
|
|
1
|
+
"use strict";const e=require("react/jsx-runtime"),S=require("react"),N=require("clsx"),a=require("./Icon-BUP5_kRs.cjs"),j=require("./names-YOCJ4B5J.cjs"),g=require("./ConfigProvider-CzAQf_d_.cjs"),h="_emptyState_1vpxy_3",f="_sm_1vpxy_17",q="_md_1vpxy_23",E="_lg_1vpxy_29",I="_icon_1vpxy_37",b="_title_1vpxy_55",C="_description_1vpxy_61",O="_action_1vpxy_70",T="_pattern_1vpxy_77",w="_tinted_1vpxy_100",t={emptyState:h,sm:f,md:q,lg:E,icon:I,title:b,description:C,action:O,pattern:T,tinted:w},z=new Set(j.ICON_NAMES),A=S.forwardRef(function({icon:n,title:_,description:c,action:i,size:d="md",pattern:p=!0,color:s,className:m,style:r,children:x,...y},u){const v=g.useT(),l=_??v("emptyState.title"),o=n===!1?null:n==null?e.jsx(a.Icon,{name:"FolderOpen"}):typeof n=="string"&&z.has(n)?e.jsx(a.Icon,{name:n}):n;return e.jsxs("div",{ref:u,className:N.clsx(t.emptyState,t[d],p&&t.pattern,s&&t.tinted,m),style:s?{"--tz-btn-rgb":`var(--tz-color-${s}-rgb)`,...r}:r,...y,children:[o!=null&&e.jsx("div",{className:t.icon,"aria-hidden":!0,children:o}),l!=null&&e.jsx("div",{className:t.title,children:l}),c!=null&&e.jsx("div",{className:t.description,children:c}),i!=null&&e.jsx("div",{className:t.action,children:i}),x]})});exports.EmptyState=A;
|
|
2
|
+
//# sourceMappingURL=EmptyState-ECc6e_En.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState-
|
|
1
|
+
{"version":3,"file":"EmptyState-ECc6e_En.cjs","sources":["../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import { forwardRef, type CSSProperties, type HTMLAttributes, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport styles from './EmptyState.module.css'\n\nexport type EmptyStateSize = 'sm' | 'md' | 'lg'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\nexport interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'color'> {\n /** Leading glyph shown in a soft circle — an `IconName`, any node, or `false` to hide it. Defaults to `FolderOpen`. */\n icon?: IconName | ReactNode | false\n /** Heading line. Defaults to `\"No Results Found\"`. */\n title?: ReactNode\n /** Muted description under the title (e.g. a hint on what to do next). */\n description?: ReactNode\n /** Action slot under the text — e.g. an \"Add Item\" or \"Clear Filters\" button. */\n action?: ReactNode\n /** Size — scales the icon, text, and vertical padding. Defaults to `md`. */\n size?: EmptyStateSize\n /**\n * Polished \"hero\" look: a faded grid backdrop (fades out toward the edges) + an elevated icon\n * (gradient + drop shadow). Defaults to `true`; pass `pattern={false}` for the flat, compact placeholder.\n */\n pattern?: boolean\n /** Tint the icon puck with a theme color (e.g. `error` for a failure). Omitted → the neutral muted puck. */\n color?: ThemeColor\n /** Extra content rendered below the action. */\n children?: ReactNode\n}\n\n/**\n * The empty-state placeholder — drop it in wherever a page, table, list, or gallery has nothing to\n * show (no records yet, no search matches). A centered, muted glyph in a soft circle + a `title` +\n * an optional `description` and `action` (e.g. a \"Add Item\" / \"Clear Filters\" button). Neutral by\n * design; pass a custom `icon` node for a tinted glyph. Token-only styling.\n */\nexport const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(function EmptyState(\n {\n icon,\n title,\n description,\n action,\n size = 'md',\n pattern = true,\n color,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const t = useT()\n const resolvedTitle = title ?? t('emptyState.title')\n const renderedIcon =\n icon === false ? null : icon == null ? (\n <Icon name=\"FolderOpen\" />\n ) : typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} />\n ) : (\n icon\n )\n\n return (\n <div\n ref={ref}\n className={clsx(\n styles.emptyState,\n styles[size],\n pattern && styles.pattern,\n color && styles.tinted,\n className,\n )}\n style={\n (color\n ? { '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`, ...style }\n : style) as CSSProperties\n }\n {...props}\n >\n {renderedIcon != null && (\n <div className={styles.icon} aria-hidden>\n {renderedIcon}\n </div>\n )}\n {resolvedTitle != null && <div className={styles.title}>{resolvedTitle}</div>}\n {description != null && <div className={styles.description}>{description}</div>}\n {action != null && <div className={styles.action}>{action}</div>}\n {children}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","EmptyState","forwardRef","icon","title","description","action","size","pattern","color","className","style","children","props","ref","t","useT","resolvedTitle","renderedIcon","jsx","Icon","jsxs","clsx","styles"],"mappings":"2eASMA,EAAgB,IAAI,IAAYC,YAAU,EA8BnCC,EAAaC,EAAAA,WAA4C,SACpE,CACE,KAAAC,EACA,MAAAC,EACA,YAAAC,EACA,OAAAC,EACA,KAAAC,EAAO,KACP,QAAAC,EAAU,GACV,MAAAC,EACA,UAAAC,EACA,MAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,MAAMC,EAAIC,EAAAA,KAAA,EACJC,EAAgBb,GAASW,EAAE,kBAAkB,EAC7CG,EACJf,IAAS,GAAQ,KAAOA,GAAQ,KAC9BgB,MAACC,EAAAA,KAAA,CAAK,KAAK,YAAA,CAAa,EACtB,OAAOjB,GAAS,UAAYJ,EAAc,IAAII,CAAI,EACpDgB,MAACC,EAAAA,KAAA,CAAK,KAAMjB,CAAA,CAAkB,EAE9BA,EAGJ,OACEkB,EAAAA,KAAC,MAAA,CACC,IAAAP,EACA,UAAWQ,EAAAA,KACTC,EAAO,WACPA,EAAOhB,CAAI,EACXC,GAAWe,EAAO,QAClBd,GAASc,EAAO,OAChBb,CAAA,EAEF,MACGD,EACG,CAAE,eAAgB,kBAAkBA,CAAK,QAAS,GAAGE,CAAA,EACrDA,EAEL,GAAGE,EAEH,SAAA,CAAAK,GAAgB,YACd,MAAA,CAAI,UAAWK,EAAO,KAAM,cAAW,GACrC,SAAAL,CAAA,CACH,EAEDD,GAAiB,MAAQE,EAAAA,IAAC,OAAI,UAAWI,EAAO,MAAQ,SAAAN,EAAc,EACtEZ,GAAe,MAAQc,EAAAA,IAAC,OAAI,UAAWI,EAAO,YAAc,SAAAlB,EAAY,EACxEC,GAAU,MAAQa,EAAAA,IAAC,OAAI,UAAWI,EAAO,OAAS,SAAAjB,EAAO,EACzDM,CAAA,CAAA,CAAA,CAGP,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as a, jsxs as d } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as A, Component as B } from "react";
|
|
3
3
|
import { clsx as F } from "clsx";
|
|
4
|
-
import { B as z } from "./Button-
|
|
5
|
-
import { C as $ } from "./CopyButton-
|
|
6
|
-
import { E as q } from "./EmptyState-
|
|
4
|
+
import { B as z } from "./Button-BJ5Xd10u.js";
|
|
5
|
+
import { C as $ } from "./CopyButton-BNcW9-KU.js";
|
|
6
|
+
import { E as q } from "./EmptyState-CvpKSYY4.js";
|
|
7
7
|
import { I as w } from "./Icon-CGQ5yGSZ.js";
|
|
8
|
-
import { a as I } from "./ConfigProvider-
|
|
8
|
+
import { a as I } from "./ConfigProvider-D2svpXFu.js";
|
|
9
9
|
function K(t, e = (r) => `Request failed (${r})`) {
|
|
10
10
|
var c, l, n;
|
|
11
11
|
if (t == null || t === !1) return;
|
|
@@ -160,4 +160,4 @@ export {
|
|
|
160
160
|
T as d,
|
|
161
161
|
M as g
|
|
162
162
|
};
|
|
163
|
-
//# sourceMappingURL=ErrorBoundary-
|
|
163
|
+
//# sourceMappingURL=ErrorBoundary-CJx5E9wJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorBoundary-B-37hGZW.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\n/**\n * The server's **trace id** for a failed request — the handle that matches a user's report to the server\n * log. Read from `error.traceId` (e.g. an app `ApiError` carrying the response envelope's `traceId`) or an\n * axios-style `error.response.data.traceId`. `undefined` when there is none.\n */\nexport function getErrorTraceId(error: unknown): string | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { traceId?: unknown; response?: { data?: { traceId?: unknown } } }\n const id = typeof e.traceId === 'string' ? e.traceId : e.response?.data?.traceId\n return typeof id === 'string' && id.trim() ? id.trim() : undefined\n}\n\n/**\n * Per-field validation messages of a `400` — `{ field: 'message' }`. Read from `error.fieldErrors` (an app\n * `ApiError`) or an axios-style `error.response.data.errors` (ASP.NET sends a string **or** an array of\n * strings per field — the first string wins). `undefined` when there are none.\n */\nexport function getErrorFieldErrors(error: unknown): Record<string, string> | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { fieldErrors?: unknown; response?: { data?: { errors?: unknown } } }\n const raw = e.fieldErrors ?? e.response?.data?.errors\n if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) return undefined\n const out: Record<string, string> = {}\n for (const [field, message] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof message === 'string' && message.trim()) out[field] = message\n else if (Array.isArray(message) && typeof message[0] === 'string') out[field] = message[0]\n }\n return Object.keys(out).length > 0 ? out : undefined\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { CopyButton } from '../CopyButton'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport {\n getErrorDetails,\n getErrorFieldErrors,\n getErrorMessage,\n getErrorTraceId,\n} 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 * The server's trace id, shown under the message with a copy button (it matches a report to the server\n * log). Defaults to the one on `error` (`error.traceId` / `error.response.data.traceId`); `false` hides it.\n */\n traceId?: string | false\n /**\n * Per-field validation messages (`{ field: message }`), listed as the description when there's no explicit\n * `description`. Defaults to the ones on `error` (`error.fieldErrors` / `error.response.data.errors`);\n * `false` hides them. In a form, put them on the inputs instead.\n */\n fieldErrors?: Record<string, string> | false\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. The server's `traceId` (copyable) and a 400's per-field `fieldErrors` are shown\n * when the error carries them. 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 traceId: traceIdProp,\n fieldErrors: fieldErrorsProp,\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 traceId = traceIdProp === false ? undefined : (traceIdProp ?? getErrorTraceId(error))\n const fieldErrors =\n fieldErrorsProp === false ? undefined : (fieldErrorsProp ?? getErrorFieldErrors(error))\n const fieldErrorList =\n fieldErrors && Object.keys(fieldErrors).length > 0 ? (\n <ul className={styles.fieldErrors}>\n {Object.entries(fieldErrors).map(([field, msg]) => (\n <li key={field}>\n <span className={styles.field}>{field}</span> — {msg}\n </li>\n ))}\n </ul>\n ) : undefined\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 // a 400's message is the generic \"validation errors occurred\" — the per-field list is the useful part\n description={description ?? fieldErrorList ?? 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 {traceId != null && (\n <span className={styles.trace}>\n <span>\n {t('errorState.traceId')}: <code className={styles.traceId}>{traceId}</code>\n </span>\n <CopyButton value={traceId} size=\"sm\" variant=\"text\" color=\"primary\" />\n </span>\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","e","serverMessage","_b","_a","_c","getErrorDetails","getErrorTraceId","id","getErrorFieldErrors","raw","out","field","message","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","traceIdProp","fieldErrorsProp","size","pattern","action","className","children","props","ref","t","useT","traceId","fieldErrors","fieldErrorList","jsx","styles","msg","jsxs","details","retry","Button","Icon","EmptyState","clsx","CopyButton","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ErrorBoundary-CJx5E9wJ.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\n/**\n * The server's **trace id** for a failed request — the handle that matches a user's report to the server\n * log. Read from `error.traceId` (e.g. an app `ApiError` carrying the response envelope's `traceId`) or an\n * axios-style `error.response.data.traceId`. `undefined` when there is none.\n */\nexport function getErrorTraceId(error: unknown): string | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { traceId?: unknown; response?: { data?: { traceId?: unknown } } }\n const id = typeof e.traceId === 'string' ? e.traceId : e.response?.data?.traceId\n return typeof id === 'string' && id.trim() ? id.trim() : undefined\n}\n\n/**\n * Per-field validation messages of a `400` — `{ field: 'message' }`. Read from `error.fieldErrors` (an app\n * `ApiError`) or an axios-style `error.response.data.errors` (ASP.NET sends a string **or** an array of\n * strings per field — the first string wins). `undefined` when there are none.\n */\nexport function getErrorFieldErrors(error: unknown): Record<string, string> | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { fieldErrors?: unknown; response?: { data?: { errors?: unknown } } }\n const raw = e.fieldErrors ?? e.response?.data?.errors\n if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) return undefined\n const out: Record<string, string> = {}\n for (const [field, message] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof message === 'string' && message.trim()) out[field] = message\n else if (Array.isArray(message) && typeof message[0] === 'string') out[field] = message[0]\n }\n return Object.keys(out).length > 0 ? out : undefined\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { CopyButton } from '../CopyButton'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport {\n getErrorDetails,\n getErrorFieldErrors,\n getErrorMessage,\n getErrorTraceId,\n} 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 * The server's trace id, shown under the message with a copy button (it matches a report to the server\n * log). Defaults to the one on `error` (`error.traceId` / `error.response.data.traceId`); `false` hides it.\n */\n traceId?: string | false\n /**\n * Per-field validation messages (`{ field: message }`), listed as the description when there's no explicit\n * `description`. Defaults to the ones on `error` (`error.fieldErrors` / `error.response.data.errors`);\n * `false` hides them. In a form, put them on the inputs instead.\n */\n fieldErrors?: Record<string, string> | false\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. The server's `traceId` (copyable) and a 400's per-field `fieldErrors` are shown\n * when the error carries them. 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 traceId: traceIdProp,\n fieldErrors: fieldErrorsProp,\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 traceId = traceIdProp === false ? undefined : (traceIdProp ?? getErrorTraceId(error))\n const fieldErrors =\n fieldErrorsProp === false ? undefined : (fieldErrorsProp ?? getErrorFieldErrors(error))\n const fieldErrorList =\n fieldErrors && Object.keys(fieldErrors).length > 0 ? (\n <ul className={styles.fieldErrors}>\n {Object.entries(fieldErrors).map(([field, msg]) => (\n <li key={field}>\n <span className={styles.field}>{field}</span> — {msg}\n </li>\n ))}\n </ul>\n ) : undefined\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 // a 400's message is the generic \"validation errors occurred\" — the per-field list is the useful part\n description={description ?? fieldErrorList ?? 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 {traceId != null && (\n <span className={styles.trace}>\n <span>\n {t('errorState.traceId')}: <code className={styles.traceId}>{traceId}</code>\n </span>\n <CopyButton value={traceId} size=\"sm\" variant=\"text\" color=\"primary\" />\n </span>\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","e","serverMessage","_b","_a","_c","getErrorDetails","getErrorTraceId","id","getErrorFieldErrors","raw","out","field","message","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","traceIdProp","fieldErrorsProp","size","pattern","action","className","children","props","ref","t","useT","traceId","fieldErrors","fieldErrorList","jsx","styles","msg","jsxs","details","retry","Button","Icon","EmptyState","clsx","CopyButton","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const n=require("react/jsx-runtime"),v=require("react"),z=require("clsx"),M=require("./Button-
|
|
2
|
-
//# sourceMappingURL=ErrorBoundary-
|
|
1
|
+
"use strict";const n=require("react/jsx-runtime"),v=require("react"),z=require("clsx"),M=require("./Button-BZq1mIUH.cjs"),$=require("./CopyButton-DUtx2-Gi.cjs"),w=require("./EmptyState-ECc6e_En.cjs"),K=require("./Icon-BUP5_kRs.cjs"),S=require("./ConfigProvider-CzAQf_d_.cjs");function x(t,r=e=>`Request failed (${e})`){var c,u,o;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=(u=(c=e.response)==null?void 0:c.data)==null?void 0:u.message;if(typeof s=="string"&&s.trim())return s.trim();if(typeof e.message=="string"&&e.message.trim())return e.message.trim();const i=typeof e.status=="number"?e.status:(o=e.response)==null?void 0:o.status;if(typeof i=="number")return r(i)}function I(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)}}}function b(t){var s,i;if(t==null||typeof t!="object")return;const r=t,e=typeof r.traceId=="string"?r.traceId:(i=(s=r.response)==null?void 0:s.data)==null?void 0:i.traceId;return typeof e=="string"&&e.trim()?e.trim():void 0}function N(t){var i,c;if(t==null||typeof t!="object")return;const r=t,e=r.fieldErrors??((c=(i=r.response)==null?void 0:i.data)==null?void 0:c.errors);if(e==null||typeof e!="object"||Array.isArray(e))return;const s={};for(const[u,o]of Object.entries(e))typeof o=="string"&&o.trim()?s[u]=o:Array.isArray(o)&&typeof o[0]=="string"&&(s[u]=o[0]);return Object.keys(s).length>0?s:void 0}const V="_errorState_iuur1_4",J="_actions_iuur1_9",L="_fieldErrors_iuur1_18",U="_field_iuur1_18",G="_trace_iuur1_32",H="_traceId_iuur1_39",Q="_compact_iuur1_45",W="_details_iuur1_50",X="_summary_iuur1_56",Y="_pre_iuur1_63",a={errorState:V,actions:J,fieldErrors:L,field:U,trace:G,traceId:H,compact:Q,details:W,summary:X,pre:Y},Z=typeof process<"u"&&process.env.NODE_ENV!=="production",q=v.forwardRef(function({error:r,title:e,description:s,icon:i="Danger",onRetry:c,retryLabel:u,showDetails:o="dev",compact:f=!1,traceId:y,fieldErrors:g,size:D,pattern:k,action:h,className:C,children:O,...B},R){const l=S.useT(),F=x(r,d=>l("errorState.requestFailed",{status:d})),p=y===!1?void 0:y??b(r),m=g===!1?void 0:g??N(r),A=m&&Object.keys(m).length>0?n.jsx("ul",{className:a.fieldErrors,children:Object.entries(m).map(([d,T])=>n.jsxs("li",{children:[n.jsx("span",{className:a.field,children:d})," — ",T]},d))}):void 0,E=(o==="dev"?Z:o)?I(r):void 0,_=c!=null?n.jsx(M.Button,{size:"sm",variant:"outlined",color:"primary",startIcon:n.jsx(K.Icon,{name:"RefreshRight"}),onClick:c,children:u??l("errorState.retry")}):null;return n.jsxs(w.EmptyState,{ref:R,role:"alert","aria-live":"polite",color:"error",icon:i,title:e??l("errorState.title"),description:s??A??F??l("errorState.description"),size:D??(f?"sm":"md"),pattern:k??!f,action:_||h?n.jsxs("span",{className:a.actions,children:[_,h]}):void 0,className:z.clsx(a.errorState,f&&a.compact,C),...B,children:[p!=null&&n.jsxs("span",{className:a.trace,children:[n.jsxs("span",{children:[l("errorState.traceId"),": ",n.jsx("code",{className:a.traceId,children:p})]}),n.jsx($.CopyButton,{value:p,size:"sm",variant:"text",color:"primary"})]}),E!=null&&n.jsxs("details",{className:a.details,children:[n.jsx("summary",{className:a.summary,children:l("errorState.details")}),n.jsx("pre",{className:a.pre,children:E})]}),O]})}),P=(t=[],r=[])=>t.length!==r.length||t.some((e,s)=>!Object.is(e,r[s])),j=t=>t instanceof Error?t:new Error(String(t));function tt({error:t,reset:r}){const e=S.useT();return n.jsx(q,{error:t,description:e("errorState.description"),onRetry:r})}class et extends v.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:j(r)}}componentDidCatch(r,e){var s,i;(i=(s=this.props).onError)==null||i.call(s,j(r),e)}componentDidUpdate(r,e){this.state.error&&e.error&&P(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(tt,{error:r,reset:this.reset})}}exports.ErrorBoundary=et;exports.ErrorState=q;exports.getErrorDetails=I;exports.getErrorFieldErrors=N;exports.getErrorMessage=x;exports.getErrorTraceId=b;
|
|
2
|
+
//# sourceMappingURL=ErrorBoundary-DbKRtdgS.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorBoundary-gRGxeuM1.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\n/**\n * The server's **trace id** for a failed request — the handle that matches a user's report to the server\n * log. Read from `error.traceId` (e.g. an app `ApiError` carrying the response envelope's `traceId`) or an\n * axios-style `error.response.data.traceId`. `undefined` when there is none.\n */\nexport function getErrorTraceId(error: unknown): string | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { traceId?: unknown; response?: { data?: { traceId?: unknown } } }\n const id = typeof e.traceId === 'string' ? e.traceId : e.response?.data?.traceId\n return typeof id === 'string' && id.trim() ? id.trim() : undefined\n}\n\n/**\n * Per-field validation messages of a `400` — `{ field: 'message' }`. Read from `error.fieldErrors` (an app\n * `ApiError`) or an axios-style `error.response.data.errors` (ASP.NET sends a string **or** an array of\n * strings per field — the first string wins). `undefined` when there are none.\n */\nexport function getErrorFieldErrors(error: unknown): Record<string, string> | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { fieldErrors?: unknown; response?: { data?: { errors?: unknown } } }\n const raw = e.fieldErrors ?? e.response?.data?.errors\n if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) return undefined\n const out: Record<string, string> = {}\n for (const [field, message] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof message === 'string' && message.trim()) out[field] = message\n else if (Array.isArray(message) && typeof message[0] === 'string') out[field] = message[0]\n }\n return Object.keys(out).length > 0 ? out : undefined\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { CopyButton } from '../CopyButton'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport {\n getErrorDetails,\n getErrorFieldErrors,\n getErrorMessage,\n getErrorTraceId,\n} 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 * The server's trace id, shown under the message with a copy button (it matches a report to the server\n * log). Defaults to the one on `error` (`error.traceId` / `error.response.data.traceId`); `false` hides it.\n */\n traceId?: string | false\n /**\n * Per-field validation messages (`{ field: message }`), listed as the description when there's no explicit\n * `description`. Defaults to the ones on `error` (`error.fieldErrors` / `error.response.data.errors`);\n * `false` hides them. In a form, put them on the inputs instead.\n */\n fieldErrors?: Record<string, string> | false\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. The server's `traceId` (copyable) and a 400's per-field `fieldErrors` are shown\n * when the error carries them. 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 traceId: traceIdProp,\n fieldErrors: fieldErrorsProp,\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 traceId = traceIdProp === false ? undefined : (traceIdProp ?? getErrorTraceId(error))\n const fieldErrors =\n fieldErrorsProp === false ? undefined : (fieldErrorsProp ?? getErrorFieldErrors(error))\n const fieldErrorList =\n fieldErrors && Object.keys(fieldErrors).length > 0 ? (\n <ul className={styles.fieldErrors}>\n {Object.entries(fieldErrors).map(([field, msg]) => (\n <li key={field}>\n <span className={styles.field}>{field}</span> — {msg}\n </li>\n ))}\n </ul>\n ) : undefined\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 // a 400's message is the generic \"validation errors occurred\" — the per-field list is the useful part\n description={description ?? fieldErrorList ?? 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 {traceId != null && (\n <span className={styles.trace}>\n <span>\n {t('errorState.traceId')}: <code className={styles.traceId}>{traceId}</code>\n </span>\n <CopyButton value={traceId} size=\"sm\" variant=\"text\" color=\"primary\" />\n </span>\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","getErrorTraceId","e","id","getErrorFieldErrors","raw","out","field","message","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","traceIdProp","fieldErrorsProp","size","pattern","action","className","children","props","ref","t","useT","traceId","fieldErrors","fieldErrorList","jsx","styles","msg","jsxs","details","retry","Button","Icon","EmptyState","clsx","CopyButton","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ErrorBoundary-DbKRtdgS.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\n/**\n * The server's **trace id** for a failed request — the handle that matches a user's report to the server\n * log. Read from `error.traceId` (e.g. an app `ApiError` carrying the response envelope's `traceId`) or an\n * axios-style `error.response.data.traceId`. `undefined` when there is none.\n */\nexport function getErrorTraceId(error: unknown): string | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { traceId?: unknown; response?: { data?: { traceId?: unknown } } }\n const id = typeof e.traceId === 'string' ? e.traceId : e.response?.data?.traceId\n return typeof id === 'string' && id.trim() ? id.trim() : undefined\n}\n\n/**\n * Per-field validation messages of a `400` — `{ field: 'message' }`. Read from `error.fieldErrors` (an app\n * `ApiError`) or an axios-style `error.response.data.errors` (ASP.NET sends a string **or** an array of\n * strings per field — the first string wins). `undefined` when there are none.\n */\nexport function getErrorFieldErrors(error: unknown): Record<string, string> | undefined {\n if (error == null || typeof error !== 'object') return undefined\n const e = error as { fieldErrors?: unknown; response?: { data?: { errors?: unknown } } }\n const raw = e.fieldErrors ?? e.response?.data?.errors\n if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) return undefined\n const out: Record<string, string> = {}\n for (const [field, message] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof message === 'string' && message.trim()) out[field] = message\n else if (Array.isArray(message) && typeof message[0] === 'string') out[field] = message[0]\n }\n return Object.keys(out).length > 0 ? out : undefined\n}\n","import { forwardRef, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Button } from '../Button'\nimport { CopyButton } from '../CopyButton'\nimport { EmptyState, type EmptyStateProps } from '../EmptyState'\nimport { Icon } from '../Icon'\nimport type { IconName } from '../../icons/names'\nimport {\n getErrorDetails,\n getErrorFieldErrors,\n getErrorMessage,\n getErrorTraceId,\n} 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 * The server's trace id, shown under the message with a copy button (it matches a report to the server\n * log). Defaults to the one on `error` (`error.traceId` / `error.response.data.traceId`); `false` hides it.\n */\n traceId?: string | false\n /**\n * Per-field validation messages (`{ field: message }`), listed as the description when there's no explicit\n * `description`. Defaults to the ones on `error` (`error.fieldErrors` / `error.response.data.errors`);\n * `false` hides them. In a form, put them on the inputs instead.\n */\n fieldErrors?: Record<string, string> | false\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. The server's `traceId` (copyable) and a 400's per-field `fieldErrors` are shown\n * when the error carries them. 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 traceId: traceIdProp,\n fieldErrors: fieldErrorsProp,\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 traceId = traceIdProp === false ? undefined : (traceIdProp ?? getErrorTraceId(error))\n const fieldErrors =\n fieldErrorsProp === false ? undefined : (fieldErrorsProp ?? getErrorFieldErrors(error))\n const fieldErrorList =\n fieldErrors && Object.keys(fieldErrors).length > 0 ? (\n <ul className={styles.fieldErrors}>\n {Object.entries(fieldErrors).map(([field, msg]) => (\n <li key={field}>\n <span className={styles.field}>{field}</span> — {msg}\n </li>\n ))}\n </ul>\n ) : undefined\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 // a 400's message is the generic \"validation errors occurred\" — the per-field list is the useful part\n description={description ?? fieldErrorList ?? 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 {traceId != null && (\n <span className={styles.trace}>\n <span>\n {t('errorState.traceId')}: <code className={styles.traceId}>{traceId}</code>\n </span>\n <CopyButton value={traceId} size=\"sm\" variant=\"text\" color=\"primary\" />\n </span>\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","getErrorTraceId","e","id","getErrorFieldErrors","raw","out","field","message","IS_DEV","ErrorState","forwardRef","title","description","icon","onRetry","retryLabel","showDetails","compact","traceIdProp","fieldErrorsProp","size","pattern","action","className","children","props","ref","t","useT","traceId","fieldErrors","fieldErrorList","jsx","styles","msg","jsxs","details","retry","Button","Icon","EmptyState","clsx","CopyButton","keysChanged","a","b","v","i","toError","value","DefaultFallback","reset","ErrorBoundary","Component","info","prev","prevState","fallback"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const o=require("react/jsx-runtime"),u=require("react"),M=require("clsx"),S=require("./Avatar-CQ--wGWS.cjs"),A=require("./IconButton-
|
|
2
|
-
//# sourceMappingURL=FileCard-
|
|
1
|
+
"use strict";const o=require("react/jsx-runtime"),u=require("react"),M=require("clsx"),S=require("./Avatar-CQ--wGWS.cjs"),A=require("./IconButton-V8tjArlt.cjs"),O=require("./Icon-BUP5_kRs.cjs"),L=require("./Typography-B6ASPrzT.cjs"),$=require("./ConfigProvider-CzAQf_d_.cjs"),V="_fileCard_kpeb5_3",G="_avatar_kpeb5_24",R="_body_kpeb5_29",H="_name_kpeb5_38",K="_nameBase_kpeb5_45",P="_nameExt_kpeb5_51",U="_type_kpeb5_57",W="_download_kpeb5_61",X="_sm_kpeb5_66",z="_md_kpeb5_77",J="_lg_kpeb5_81",s={fileCard:V,avatar:G,body:R,name:H,nameBase:K,nameExt:P,type:U,download:W,sm:X,md:z,lg:J},Q=new Set(["png","jpg","jpeg","webp","svg","gif","avif","bmp","ico","heic"]),Y={pdf:"DocumentText",doc:"DocumentText",docx:"DocumentText",txt:"DocumentText",rtf:"DocumentText",md:"DocumentText",csv:"DocumentText",xls:"DocumentText",xlsx:"DocumentText",json:"DocumentCode",xml:"DocumentCode",zip:"Folder",rar:"Folder","7z":"Folder",mp4:"VideoSquare",mov:"VideoSquare",webm:"VideoSquare",mp3:"MusicSquare",wav:"MusicSquare"};function Z(n,e){const t=n.lastIndexOf(".");return t>0&&n.length-t<=7?n.slice(t+1).toLowerCase():e&&e.includes("/")?e.slice(e.indexOf("/")+1).toLowerCase():""}function ee(n){const e=n.lastIndexOf(".");return e>0&&n.length-e<=7?{base:n.slice(0,e),ext:n.slice(e)}:{base:n,ext:""}}function g(n){if(!Number.isFinite(n)||n<0)return"";if(n<1024)return`${n} B`;const e=["KB","MB","GB","TB"];let t=n/1024,a=0;for(;t>=1024&&a<e.length-1;)t/=1024,a+=1;return`${t<10?t.toFixed(1):Math.round(t)} ${e[a]}`}const te=u.forwardRef(function({name:e,src:t,type:a,image:v,fileSize:c,fetchSize:m=!1,meta:C,color:x="accent",size:d="md",downloadable:T=!0,onDownload:i,className:j,style:q,...w},k){const B=$.useT(),l=Z(e,a),f=v??((a==null?void 0:a.startsWith("image/"))||Q.has(l)),{base:D,ext:_}=ee(e),[p,N]=u.useState(null);u.useEffect(()=>{if(!m||c!=null||!t||typeof fetch>"u")return;let r=!1;return fetch(t,{method:"HEAD"}).then(y=>{const b=y.headers.get("content-length");!r&&b&&N(Number(b))}).catch(()=>{}),()=>{r=!0}},[m,c,t]);const E=c!=null?typeof c=="number"?g(c):c:p!=null?g(p):"",I=[l?l.toUpperCase():"",E].filter(Boolean).join(" · "),h=C??(I||null),F=()=>{if(i)return i();if(!t)return;const r=document.createElement("a");r.href=t,r.download=e,r.rel="noopener",r.click()};return o.jsxs("div",{ref:k,className:M.clsx(s.fileCard,s[d],j),style:{"--tz-btn-rgb":`var(--tz-color-${x}-rgb)`,...q},...w,children:[o.jsx(S.Avatar,{className:s.avatar,src:f?t:void 0,icon:f?void 0:Y[l]??"Document",name:e,shape:"square",size:d,color:x}),o.jsxs("div",{className:s.body,children:[o.jsxs("span",{className:s.name,title:e,children:[o.jsx("span",{className:s.nameBase,children:D}),_&&o.jsx("span",{className:s.nameExt,children:_})]}),h!=null&&o.jsx(L.Typography,{as:"span",variant:"bodySmall",color:"muted",uppercase:!0,className:s.type,children:h})]}),T&&(t||i)&&o.jsx(A.IconButton,{variant:"filled",size:d==="lg"?"md":"sm",className:s.download,"aria-label":B("fileCard.download",{name:e}),onClick:F,children:o.jsx(O.Icon,{name:"ImportArrow"})})]})});exports.FileCard=te;
|
|
2
|
+
//# sourceMappingURL=FileCard-Bjqsgi7S.cjs.map
|