@techzyapp/ui-library 1.0.49 → 1.0.51
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/{Accordion-DOrTQJB9.js → Accordion-C6vW_OMd.js} +2 -2
- package/dist/{Accordion-DOrTQJB9.js.map → Accordion-C6vW_OMd.js.map} +1 -1
- package/dist/{Accordion-CFyeLfPT.cjs → Accordion-Icvl9S8c.cjs} +2 -2
- package/dist/{Accordion-CFyeLfPT.cjs.map → Accordion-Icvl9S8c.cjs.map} +1 -1
- package/dist/{AdminRoot-CGf-Q8Hs.cjs → AdminRoot-CFDMjB1A.cjs} +2 -2
- package/dist/{AdminRoot-CGf-Q8Hs.cjs.map → AdminRoot-CFDMjB1A.cjs.map} +1 -1
- package/dist/{AdminRoot-DYM9r25r.js → AdminRoot-D4GGvprQ.js} +9 -9
- package/dist/{AdminRoot-DYM9r25r.js.map → AdminRoot-D4GGvprQ.js.map} +1 -1
- package/dist/{Alert-QvfNBhlU.cjs → Alert-CC4gxX9w.cjs} +2 -2
- package/dist/{Alert-QvfNBhlU.cjs.map → Alert-CC4gxX9w.cjs.map} +1 -1
- package/dist/{Alert-Bo_XgY-A.js → Alert-D56N-LeR.js} +4 -4
- package/dist/{Alert-Bo_XgY-A.js.map → Alert-D56N-LeR.js.map} +1 -1
- package/dist/{AuthGuard-Ck31lvBA.js → AuthGuard-D6_sTASu.js} +2 -2
- package/dist/{AuthGuard-Ck31lvBA.js.map → AuthGuard-D6_sTASu.js.map} +1 -1
- package/dist/{AuthGuard-C2eA3mJA.cjs → AuthGuard-DM1nDTE5.cjs} +2 -2
- package/dist/{AuthGuard-C2eA3mJA.cjs.map → AuthGuard-DM1nDTE5.cjs.map} +1 -1
- package/dist/{AuthLayout-BI1wLuDl.js → AuthLayout-BDRJFSpi.js} +2 -2
- package/dist/{AuthLayout-BI1wLuDl.js.map → AuthLayout-BDRJFSpi.js.map} +1 -1
- package/dist/{AuthLayout-Bzlsvicf.cjs → AuthLayout-D7mSMdM4.cjs} +2 -2
- package/dist/{AuthLayout-Bzlsvicf.cjs.map → AuthLayout-D7mSMdM4.cjs.map} +1 -1
- package/dist/{Avatar-BBqX1732.cjs → Avatar-BwGJl-ru.cjs} +2 -2
- package/dist/{Avatar-BBqX1732.cjs.map → Avatar-BwGJl-ru.cjs.map} +1 -1
- package/dist/{Avatar-CaYyv5wk.js → Avatar-C4qgzth2.js} +2 -2
- package/dist/{Avatar-CaYyv5wk.js.map → Avatar-C4qgzth2.js.map} +1 -1
- package/dist/{AvatarGroup-DrkzAt1-.cjs → AvatarGroup-B8u8ONs5.cjs} +2 -2
- package/dist/{AvatarGroup-DrkzAt1-.cjs.map → AvatarGroup-B8u8ONs5.cjs.map} +1 -1
- package/dist/{AvatarGroup-6fhm-van.js → AvatarGroup-BqxTFzRc.js} +2 -2
- package/dist/{AvatarGroup-6fhm-van.js.map → AvatarGroup-BqxTFzRc.js.map} +1 -1
- package/dist/BottomSheet-0oqSWjBx.js +646 -0
- package/dist/BottomSheet-0oqSWjBx.js.map +1 -0
- package/dist/BottomSheet-BWTYMGOU.cjs +2 -0
- package/dist/BottomSheet-BWTYMGOU.cjs.map +1 -0
- package/dist/{Breadcrumbs-BEv57tuJ.js → Breadcrumbs-BEcEVdRt.js} +4 -4
- package/dist/{Breadcrumbs-BEv57tuJ.js.map → Breadcrumbs-BEcEVdRt.js.map} +1 -1
- package/dist/{Breadcrumbs-CqGS32x5.cjs → Breadcrumbs-DGyb8ntF.cjs} +2 -2
- package/dist/{Breadcrumbs-CqGS32x5.cjs.map → Breadcrumbs-DGyb8ntF.cjs.map} +1 -1
- package/dist/{Button-DZWYeAno.js → Button-CwwuhATn.js} +2 -2
- package/dist/{Button-DZWYeAno.js.map → Button-CwwuhATn.js.map} +1 -1
- package/dist/{Button-BtiFpRie.cjs → Button-D6f4SooD.cjs} +2 -2
- package/dist/{Button-BtiFpRie.cjs.map → Button-D6f4SooD.cjs.map} +1 -1
- package/dist/{Calendar-7W9xNVBZ.js → Calendar-CGLl3HmM.js} +4 -4
- package/dist/{Calendar-7W9xNVBZ.js.map → Calendar-CGLl3HmM.js.map} +1 -1
- package/dist/{Calendar-Bgh_3Vk2.cjs → Calendar-CjHLOfVw.cjs} +2 -2
- package/dist/{Calendar-Bgh_3Vk2.cjs.map → Calendar-CjHLOfVw.cjs.map} +1 -1
- package/dist/{Card-KfmWG9Uz.cjs → Card-BbfesgrZ.cjs} +2 -2
- package/dist/{Card-KfmWG9Uz.cjs.map → Card-BbfesgrZ.cjs.map} +1 -1
- package/dist/{Card-ckOd617g.js → Card-DTmvoxKG.js} +4 -4
- package/dist/{Card-ckOd617g.js.map → Card-DTmvoxKG.js.map} +1 -1
- package/dist/{Chip-BDUsue_R.cjs → Chip-CguuQYqY.cjs} +2 -2
- package/dist/{Chip-BDUsue_R.cjs.map → Chip-CguuQYqY.cjs.map} +1 -1
- package/dist/{Chip-Crzm7Eux.js → Chip-DRwzCG96.js} +3 -3
- package/dist/{Chip-Crzm7Eux.js.map → Chip-DRwzCG96.js.map} +1 -1
- package/dist/{ChoiceCardGroup-D37XREKV.js → ChoiceCardGroup-BBqUbFLS.js} +2 -2
- package/dist/{ChoiceCardGroup-D37XREKV.js.map → ChoiceCardGroup-BBqUbFLS.js.map} +1 -1
- package/dist/{ChoiceCardGroup-Cj_YFj6C.cjs → ChoiceCardGroup-bnKFPDYz.cjs} +2 -2
- package/dist/{ChoiceCardGroup-Cj_YFj6C.cjs.map → ChoiceCardGroup-bnKFPDYz.cjs.map} +1 -1
- package/dist/{CodeBlock-CX8_dMPD.js → CodeBlock-C-8MTy4V.js} +4 -4
- package/dist/{CodeBlock-CX8_dMPD.js.map → CodeBlock-C-8MTy4V.js.map} +1 -1
- package/dist/{CodeBlock-rnGAu2DQ.cjs → CodeBlock-Dv7hXdPl.cjs} +2 -2
- package/dist/{CodeBlock-rnGAu2DQ.cjs.map → CodeBlock-Dv7hXdPl.cjs.map} +1 -1
- package/dist/{ColorPicker-BaAdcqR9.cjs → ColorPicker-B4UqiIvG.cjs} +2 -2
- package/dist/{ColorPicker-BaAdcqR9.cjs.map → ColorPicker-B4UqiIvG.cjs.map} +1 -1
- package/dist/{ColorPicker-CwLivdAt.js → ColorPicker-Rva-0w3d.js} +3 -3
- package/dist/{ColorPicker-CwLivdAt.js.map → ColorPicker-Rva-0w3d.js.map} +1 -1
- package/dist/{ColorPickerPanel-IOhJJF1R.cjs → ColorPickerPanel-DRJzClGA.cjs} +2 -2
- package/dist/{ColorPickerPanel-IOhJJF1R.cjs.map → ColorPickerPanel-DRJzClGA.cjs.map} +1 -1
- package/dist/{ColorPickerPanel-CkrSIf35.js → ColorPickerPanel-Dx_TIReY.js} +3 -3
- package/dist/{ColorPickerPanel-CkrSIf35.js.map → ColorPickerPanel-Dx_TIReY.js.map} +1 -1
- package/dist/{ColorRamp-BCy8a7ks.cjs → ColorRamp-C5KkZS8L.cjs} +2 -2
- package/dist/{ColorRamp-BCy8a7ks.cjs.map → ColorRamp-C5KkZS8L.cjs.map} +1 -1
- package/dist/{ColorRamp-DbFOsspz.js → ColorRamp-CBkbpBHf.js} +2 -2
- package/dist/{ColorRamp-DbFOsspz.js.map → ColorRamp-CBkbpBHf.js.map} +1 -1
- package/dist/{ConfigProvider-DtyUlWk6.js → ConfigProvider-BOcVBt4M.js} +2 -2
- package/dist/{ConfigProvider-DtyUlWk6.js.map → ConfigProvider-BOcVBt4M.js.map} +1 -1
- package/dist/{ConfigProvider-CYSpuSMJ.cjs → ConfigProvider-DPk0aHDG.cjs} +2 -2
- package/dist/{ConfigProvider-CYSpuSMJ.cjs.map → ConfigProvider-DPk0aHDG.cjs.map} +1 -1
- package/dist/{CopyButton-LURMuaYw.js → CopyButton-BjNknp73.js} +4 -4
- package/dist/{CopyButton-LURMuaYw.js.map → CopyButton-BjNknp73.js.map} +1 -1
- package/dist/{CopyButton-DUG5s3TM.cjs → CopyButton-BxOhFQiM.cjs} +2 -2
- package/dist/{CopyButton-DUG5s3TM.cjs.map → CopyButton-BxOhFQiM.cjs.map} +1 -1
- package/dist/{DashedButton-BX8hfY1x.cjs → DashedButton-CZ2hjLxT.cjs} +2 -2
- package/dist/{DashedButton-BX8hfY1x.cjs.map → DashedButton-CZ2hjLxT.cjs.map} +1 -1
- package/dist/{DashedButton-wcmXTYBw.js → DashedButton-meJSIY61.js} +2 -2
- package/dist/{DashedButton-wcmXTYBw.js.map → DashedButton-meJSIY61.js.map} +1 -1
- package/dist/{DatePicker-Bw9gLB8o.cjs → DatePicker-DCCq8OCQ.cjs} +2 -2
- package/dist/{DatePicker-Bw9gLB8o.cjs.map → DatePicker-DCCq8OCQ.cjs.map} +1 -1
- package/dist/{DatePicker-CSIBYSZt.js → DatePicker-UCzOaIUQ.js} +5 -5
- package/dist/{DatePicker-CSIBYSZt.js.map → DatePicker-UCzOaIUQ.js.map} +1 -1
- package/dist/{DateTimePicker-C9F2yJMf.js → DateTimePicker-1716FCsy.js} +8 -8
- package/dist/{DateTimePicker-C9F2yJMf.js.map → DateTimePicker-1716FCsy.js.map} +1 -1
- package/dist/{DateTimePicker-kikKdt0F.cjs → DateTimePicker-nN9Okf1Y.cjs} +2 -2
- package/dist/{DateTimePicker-kikKdt0F.cjs.map → DateTimePicker-nN9Okf1Y.cjs.map} +1 -1
- package/dist/{DescriptionList-kfNXbf_D.js → DescriptionList-BTdmaD1T.js} +5 -5
- package/dist/{DescriptionList-kfNXbf_D.js.map → DescriptionList-BTdmaD1T.js.map} +1 -1
- package/dist/{DescriptionList-DnGkHdzT.cjs → DescriptionList-BbLVh3eI.cjs} +2 -2
- package/dist/{DescriptionList-DnGkHdzT.cjs.map → DescriptionList-BbLVh3eI.cjs.map} +1 -1
- package/dist/{Dropdown-D-D_Z1Jo.js → Dropdown-CmEWQTdx.js} +2 -2
- package/dist/{Dropdown-D-D_Z1Jo.js.map → Dropdown-CmEWQTdx.js.map} +1 -1
- package/dist/{Dropdown-C_y9_dVn.cjs → Dropdown-DC0Cl9Tb.cjs} +2 -2
- package/dist/{Dropdown-C_y9_dVn.cjs.map → Dropdown-DC0Cl9Tb.cjs.map} +1 -1
- package/dist/{EmptyState-DrSj2XV_.js → EmptyState-Cd1IxApj.js} +3 -3
- package/dist/{EmptyState-DrSj2XV_.js.map → EmptyState-Cd1IxApj.js.map} +1 -1
- package/dist/{EmptyState-BM5LrRLq.cjs → EmptyState-DQJ1JswD.cjs} +2 -2
- package/dist/{EmptyState-BM5LrRLq.cjs.map → EmptyState-DQJ1JswD.cjs.map} +1 -1
- package/dist/{ErrorBoundary-yz669VEu.cjs → ErrorBoundary-CXhzkfEl.cjs} +2 -2
- package/dist/{ErrorBoundary-yz669VEu.cjs.map → ErrorBoundary-CXhzkfEl.cjs.map} +1 -1
- package/dist/{ErrorBoundary-DsP4hO_V.js → ErrorBoundary-DUbPB1_a.js} +3 -3
- package/dist/{ErrorBoundary-DsP4hO_V.js.map → ErrorBoundary-DUbPB1_a.js.map} +1 -1
- package/dist/{ErrorState-DEngucdq.js → ErrorState-CbKuo8cI.js} +8 -8
- package/dist/{ErrorState-DEngucdq.js.map → ErrorState-CbKuo8cI.js.map} +1 -1
- package/dist/{ErrorState-BThPIYaM.cjs → ErrorState-URYycye9.cjs} +2 -2
- package/dist/{ErrorState-BThPIYaM.cjs.map → ErrorState-URYycye9.cjs.map} +1 -1
- package/dist/{FileCard-CmCESTQd.js → FileCard-DxwKSMN1.js} +5 -5
- package/dist/{FileCard-CmCESTQd.js.map → FileCard-DxwKSMN1.js.map} +1 -1
- package/dist/{FileCard-wxDT2rj9.cjs → FileCard-o7zymUXi.cjs} +2 -2
- package/dist/{FileCard-wxDT2rj9.cjs.map → FileCard-o7zymUXi.cjs.map} +1 -1
- package/dist/{FileUploader-Dp1r4Sxc.js → FileUploader-CS5HbKW3.js} +7 -7
- package/dist/{FileUploader-Dp1r4Sxc.js.map → FileUploader-CS5HbKW3.js.map} +1 -1
- package/dist/{FileUploader-DBNRp5eT.cjs → FileUploader-uaTl82eB.cjs} +2 -2
- package/dist/{FileUploader-DBNRp5eT.cjs.map → FileUploader-uaTl82eB.cjs.map} +1 -1
- package/dist/{Flag-B6OhgwZr.cjs → Flag-BodaDmHB.cjs} +2 -2
- package/dist/{Flag-B6OhgwZr.cjs.map → Flag-BodaDmHB.cjs.map} +1 -1
- package/dist/{Flag-Q3vI7cgt.js → Flag-CS4SH1Nt.js} +2 -2
- package/dist/{Flag-Q3vI7cgt.js.map → Flag-CS4SH1Nt.js.map} +1 -1
- package/dist/{FullscreenToggle-DVdQriWB.cjs → FullscreenToggle--qqOi3Bw.cjs} +2 -2
- package/dist/{FullscreenToggle-DVdQriWB.cjs.map → FullscreenToggle--qqOi3Bw.cjs.map} +1 -1
- package/dist/{FullscreenToggle-WGsbE3Op.js → FullscreenToggle-CI3fmt9Q.js} +4 -4
- package/dist/{FullscreenToggle-WGsbE3Op.js.map → FullscreenToggle-CI3fmt9Q.js.map} +1 -1
- package/dist/Icon-BoQmbW7j.cjs +2 -0
- package/dist/Icon-BoQmbW7j.cjs.map +1 -0
- package/dist/{Icon-B7DJn8Tw.js → Icon-DMMO32p6.js} +72 -71
- package/dist/Icon-DMMO32p6.js.map +1 -0
- package/dist/{IconButton-iWbUJAz7.js → IconButton-CCxNWwlu.js} +2 -2
- package/dist/{IconButton-iWbUJAz7.js.map → IconButton-CCxNWwlu.js.map} +1 -1
- package/dist/{IconButton-DSPdv-oI.cjs → IconButton-DOlCOuKu.cjs} +2 -2
- package/dist/{IconButton-DSPdv-oI.cjs.map → IconButton-DOlCOuKu.cjs.map} +1 -1
- package/dist/{ImageEditor-BDNys8pq.js → ImageEditor-CKfaHNGz.js} +8 -8
- package/dist/{ImageEditor-BDNys8pq.js.map → ImageEditor-CKfaHNGz.js.map} +1 -1
- package/dist/{ImageEditor-C40dp2-V.cjs → ImageEditor-CWISFJ1J.cjs} +2 -2
- package/dist/{ImageEditor-C40dp2-V.cjs.map → ImageEditor-CWISFJ1J.cjs.map} +1 -1
- package/dist/{List-CLUXeaXS.cjs → List-4VSERgRp.cjs} +2 -2
- package/dist/{List-CLUXeaXS.cjs.map → List-4VSERgRp.cjs.map} +1 -1
- package/dist/{List-DS91CZUt.js → List-H70lnOLB.js} +2 -2
- package/dist/{List-DS91CZUt.js.map → List-H70lnOLB.js.map} +1 -1
- package/dist/ListItem-DRzwCAvN.js +79 -0
- package/dist/ListItem-DRzwCAvN.js.map +1 -0
- package/dist/ListItem-wMTmx1yX.cjs +2 -0
- package/dist/ListItem-wMTmx1yX.cjs.map +1 -0
- package/dist/{Loader-RyFTP2X5.cjs → Loader-DUp5O6pO.cjs} +2 -2
- package/dist/{Loader-RyFTP2X5.cjs.map → Loader-DUp5O6pO.cjs.map} +1 -1
- package/dist/{Loader-DD1vfqmN.js → Loader-Dj_lwZT2.js} +2 -2
- package/dist/{Loader-DD1vfqmN.js.map → Loader-Dj_lwZT2.js.map} +1 -1
- package/dist/{LocationPicker-DpmYaYyd.js → LocationPicker-CB2vrhu0.js} +8 -8
- package/dist/{LocationPicker-DpmYaYyd.js.map → LocationPicker-CB2vrhu0.js.map} +1 -1
- package/dist/{LocationPicker-B594f0bz.cjs → LocationPicker-DzCmt8Xb.cjs} +2 -2
- package/dist/{LocationPicker-B594f0bz.cjs.map → LocationPicker-DzCmt8Xb.cjs.map} +1 -1
- package/dist/{Modal-7cCok6fV.cjs → Modal-C5sKj4UK.cjs} +2 -2
- package/dist/{Modal-7cCok6fV.cjs.map → Modal-C5sKj4UK.cjs.map} +1 -1
- package/dist/{Modal-DVGTD2Ck.js → Modal-Cr1aqYgb.js} +4 -4
- package/dist/{Modal-DVGTD2Ck.js.map → Modal-Cr1aqYgb.js.map} +1 -1
- package/dist/{MultiSelect-D-X833xt.js → MultiSelect-DgrL23Nr.js} +5 -5
- package/dist/{MultiSelect-D-X833xt.js.map → MultiSelect-DgrL23Nr.js.map} +1 -1
- package/dist/{MultiSelect-DTKNjUDH.cjs → MultiSelect-mY7X3O7V.cjs} +2 -2
- package/dist/{MultiSelect-DTKNjUDH.cjs.map → MultiSelect-mY7X3O7V.cjs.map} +1 -1
- package/dist/{NumberField-Xz4yQMlm.cjs → NumberField-CnsHPDuN.cjs} +2 -2
- package/dist/{NumberField-Xz4yQMlm.cjs.map → NumberField-CnsHPDuN.cjs.map} +1 -1
- package/dist/{NumberField-OPOl0Yph.js → NumberField-GxQeV07e.js} +4 -4
- package/dist/{NumberField-OPOl0Yph.js.map → NumberField-GxQeV07e.js.map} +1 -1
- package/dist/{OtpField-kd0YghZq.cjs → OtpField-Dt71t0PF.cjs} +2 -2
- package/dist/{OtpField-kd0YghZq.cjs.map → OtpField-Dt71t0PF.cjs.map} +1 -1
- package/dist/{OtpField-CLrDMNtS.js → OtpField-b31rUMV1.js} +2 -2
- package/dist/{OtpField-CLrDMNtS.js.map → OtpField-b31rUMV1.js.map} +1 -1
- package/dist/{PageError-BIiZDzey.js → PageError-0it6u2r9.js} +5 -5
- package/dist/{PageError-BIiZDzey.js.map → PageError-0it6u2r9.js.map} +1 -1
- package/dist/{PageError-v6MAH_OL.cjs → PageError-BYIkzEfs.cjs} +2 -2
- package/dist/{PageError-v6MAH_OL.cjs.map → PageError-BYIkzEfs.cjs.map} +1 -1
- package/dist/{PageLayout-DH3jochw.cjs → PageLayout-8ZHBwDeC.cjs} +2 -2
- package/dist/{PageLayout-DH3jochw.cjs.map → PageLayout-8ZHBwDeC.cjs.map} +1 -1
- package/dist/{PageLayout-BjaPfXvb.js → PageLayout-Cqb2pczH.js} +5 -5
- package/dist/{PageLayout-BjaPfXvb.js.map → PageLayout-Cqb2pczH.js.map} +1 -1
- package/dist/{PageNotFound-Cse4bROv.cjs → PageNotFound-BCX-XQLA.cjs} +2 -2
- package/dist/{PageNotFound-Cse4bROv.cjs.map → PageNotFound-BCX-XQLA.cjs.map} +1 -1
- package/dist/{PageNotFound-C1oSsMG-.js → PageNotFound-ChpqEtgV.js} +5 -5
- package/dist/{PageNotFound-C1oSsMG-.js.map → PageNotFound-ChpqEtgV.js.map} +1 -1
- package/dist/{Pagination-DkmfEmgK.cjs → Pagination-DSdcF9UF.cjs} +2 -2
- package/dist/{Pagination-DkmfEmgK.cjs.map → Pagination-DSdcF9UF.cjs.map} +1 -1
- package/dist/{Pagination-BNJdqcu4.js → Pagination-Du6tATTZ.js} +3 -3
- package/dist/{Pagination-BNJdqcu4.js.map → Pagination-Du6tATTZ.js.map} +1 -1
- package/dist/{PaletteField-DqZl1mK0.cjs → PaletteField-D_wYeYEx.cjs} +2 -2
- package/dist/{PaletteField-DqZl1mK0.cjs.map → PaletteField-D_wYeYEx.cjs.map} +1 -1
- package/dist/{PaletteField-Cdky6Zka.js → PaletteField-F-6hF1Ly.js} +3 -3
- package/dist/{PaletteField-Cdky6Zka.js.map → PaletteField-F-6hF1Ly.js.map} +1 -1
- package/dist/{PhoneField-jq-3_i_b.cjs → PhoneField-BdRlvj7L.cjs} +2 -2
- package/dist/{PhoneField-jq-3_i_b.cjs.map → PhoneField-BdRlvj7L.cjs.map} +1 -1
- package/dist/{PhoneField-DmFaJJEa.js → PhoneField-D99W6Abz.js} +5 -5
- package/dist/{PhoneField-DmFaJJEa.js.map → PhoneField-D99W6Abz.js.map} +1 -1
- package/dist/{Popconfirm-KOE9gGi6.cjs → Popconfirm-B4506C47.cjs} +2 -2
- package/dist/{Popconfirm-KOE9gGi6.cjs.map → Popconfirm-B4506C47.cjs.map} +1 -1
- package/dist/{Popconfirm-D-8ZG2WR.js → Popconfirm-C5ldh11s.js} +4 -4
- package/dist/{Popconfirm-D-8ZG2WR.js.map → Popconfirm-C5ldh11s.js.map} +1 -1
- package/dist/{Progress-CdX666FP.js → Progress-C71Yo8Mw.js} +2 -2
- package/dist/{Progress-CdX666FP.js.map → Progress-C71Yo8Mw.js.map} +1 -1
- package/dist/{Progress-7EyhPtnu.cjs → Progress-sa-c4iAK.cjs} +2 -2
- package/dist/{Progress-7EyhPtnu.cjs.map → Progress-sa-c4iAK.cjs.map} +1 -1
- package/dist/{QrCode-D7ocSDi7.js → QrCode-CMLPHVUN.js} +2 -2
- package/dist/{QrCode-D7ocSDi7.js.map → QrCode-CMLPHVUN.js.map} +1 -1
- package/dist/{QrCode-ClIJjjvF.cjs → QrCode-lWfNmqL8.cjs} +2 -2
- package/dist/{QrCode-ClIJjjvF.cjs.map → QrCode-lWfNmqL8.cjs.map} +1 -1
- package/dist/{RemoveDialog-UsSX5z8Y.cjs → RemoveDialog-C6XRG1SG.cjs} +2 -2
- package/dist/{RemoveDialog-UsSX5z8Y.cjs.map → RemoveDialog-C6XRG1SG.cjs.map} +1 -1
- package/dist/{RemoveDialog-DTzRPLaT.js → RemoveDialog-D01OLxbj.js} +6 -6
- package/dist/{RemoveDialog-DTzRPLaT.js.map → RemoveDialog-D01OLxbj.js.map} +1 -1
- package/dist/{RichTextEditor-BMctlkVC.js → RichTextEditor-BFzWo8Ih.js} +10 -10
- package/dist/{RichTextEditor-BMctlkVC.js.map → RichTextEditor-BFzWo8Ih.js.map} +1 -1
- package/dist/{RichTextEditor-Bh0Q3dIW.cjs → RichTextEditor-JpvFdJMa.cjs} +2 -2
- package/dist/{RichTextEditor-Bh0Q3dIW.cjs.map → RichTextEditor-JpvFdJMa.cjs.map} +1 -1
- package/dist/{RootLayout-CTkv4iQJ.js → RootLayout-Dbika05Y.js} +21 -21
- package/dist/{RootLayout-CTkv4iQJ.js.map → RootLayout-Dbika05Y.js.map} +1 -1
- package/dist/{RootLayout-BztZetpk.cjs → RootLayout-IwlWqYVL.cjs} +2 -2
- package/dist/{RootLayout-BztZetpk.cjs.map → RootLayout-IwlWqYVL.cjs.map} +1 -1
- package/dist/{Select-BzVyK6Ne.cjs → Select-CioU7fV7.cjs} +2 -2
- package/dist/{Select-BzVyK6Ne.cjs.map → Select-CioU7fV7.cjs.map} +1 -1
- package/dist/{Select-CmonDIIU.js → Select-DKaKdvG0.js} +4 -4
- package/dist/{Select-CmonDIIU.js.map → Select-DKaKdvG0.js.map} +1 -1
- package/dist/Sidebar-B7mCqEkl.cjs +2 -0
- package/dist/Sidebar-B7mCqEkl.cjs.map +1 -0
- package/dist/Sidebar-D0pNTtIb.js +543 -0
- package/dist/Sidebar-D0pNTtIb.js.map +1 -0
- package/dist/{Slider-C7Wb3q_F.js → Slider-BVM_MXjM.js} +2 -2
- package/dist/{Slider-C7Wb3q_F.js.map → Slider-BVM_MXjM.js.map} +1 -1
- package/dist/{Slider-Oe9VSAdy.cjs → Slider-RpFfWXLX.cjs} +2 -2
- package/dist/{Slider-Oe9VSAdy.cjs.map → Slider-RpFfWXLX.cjs.map} +1 -1
- package/dist/{SpeedDial-CCGQlwn2.js → SpeedDial-BMd4lvc6.js} +3 -3
- package/dist/{SpeedDial-CCGQlwn2.js.map → SpeedDial-BMd4lvc6.js.map} +1 -1
- package/dist/{SpeedDial-DpIXoYHB.cjs → SpeedDial-BpHZ09TN.cjs} +2 -2
- package/dist/{SpeedDial-DpIXoYHB.cjs.map → SpeedDial-BpHZ09TN.cjs.map} +1 -1
- package/dist/{Stepper-PBDU60G_.cjs → Stepper-BhtP1FgK.cjs} +2 -2
- package/dist/{Stepper-PBDU60G_.cjs.map → Stepper-BhtP1FgK.cjs.map} +1 -1
- package/dist/{Stepper-D_WKS1RG.js → Stepper-CedGw8c6.js} +3 -3
- package/dist/{Stepper-D_WKS1RG.js.map → Stepper-CedGw8c6.js.map} +1 -1
- package/dist/{SwatchPicker-DS4WY2eM.js → SwatchPicker-BI0XHphv.js} +2 -2
- package/dist/{SwatchPicker-DS4WY2eM.js.map → SwatchPicker-BI0XHphv.js.map} +1 -1
- package/dist/{SwatchPicker-DCjE0T80.cjs → SwatchPicker-QYtqEUxX.cjs} +2 -2
- package/dist/{SwatchPicker-DCjE0T80.cjs.map → SwatchPicker-QYtqEUxX.cjs.map} +1 -1
- package/dist/{Table-CZ4n4-TN.cjs → Table-C-s1M3ZJ.cjs} +2 -2
- package/dist/{Table-CZ4n4-TN.cjs.map → Table-C-s1M3ZJ.cjs.map} +1 -1
- package/dist/{Table-DZQVa_PE.js → Table-CEIZw6O7.js} +19 -19
- package/dist/{Table-DZQVa_PE.js.map → Table-CEIZw6O7.js.map} +1 -1
- package/dist/{Tabs-B063mP-v.js → Tabs-BryFjibj.js} +3 -3
- package/dist/{Tabs-B063mP-v.js.map → Tabs-BryFjibj.js.map} +1 -1
- package/dist/{Tabs-Byhqm-TE.cjs → Tabs-DXb1phlV.cjs} +2 -2
- package/dist/{Tabs-Byhqm-TE.cjs.map → Tabs-DXb1phlV.cjs.map} +1 -1
- package/dist/{TagsField-g_LtwYgz.cjs → TagsField-BG7ianZI.cjs} +2 -2
- package/dist/{TagsField-g_LtwYgz.cjs.map → TagsField-BG7ianZI.cjs.map} +1 -1
- package/dist/{TagsField-hQFYyNcM.js → TagsField-Dju_vk92.js} +5 -5
- package/dist/{TagsField-hQFYyNcM.js.map → TagsField-Dju_vk92.js.map} +1 -1
- package/dist/{TextField-D4s2hGSd.cjs → TextField-D5NDKrbU.cjs} +2 -2
- package/dist/{TextField-D4s2hGSd.cjs.map → TextField-D5NDKrbU.cjs.map} +1 -1
- package/dist/{TextField-Dfpk0jOg.js → TextField-DATNsTzX.js} +4 -4
- package/dist/{TextField-Dfpk0jOg.js.map → TextField-DATNsTzX.js.map} +1 -1
- package/dist/{ThemeToggle-BQQ3eswr.js → ThemeToggle-CCSi6b_Z.js} +4 -4
- package/dist/{ThemeToggle-BQQ3eswr.js.map → ThemeToggle-CCSi6b_Z.js.map} +1 -1
- package/dist/{ThemeToggle-BTTI7Jz0.cjs → ThemeToggle-or27hawd.cjs} +2 -2
- package/dist/{ThemeToggle-BTTI7Jz0.cjs.map → ThemeToggle-or27hawd.cjs.map} +1 -1
- package/dist/{TimeColumns-BpjhrNCq.js → TimeColumns-B5LAStb0.js} +2 -2
- package/dist/{TimeColumns-BpjhrNCq.js.map → TimeColumns-B5LAStb0.js.map} +1 -1
- package/dist/{TimeColumns-DZYGWWG_.cjs → TimeColumns-BNmC-5do.cjs} +2 -2
- package/dist/{TimeColumns-DZYGWWG_.cjs.map → TimeColumns-BNmC-5do.cjs.map} +1 -1
- package/dist/{TimePicker-DChtZgBs.cjs → TimePicker-CKNymi90.cjs} +2 -2
- package/dist/{TimePicker-DChtZgBs.cjs.map → TimePicker-CKNymi90.cjs.map} +1 -1
- package/dist/{TimePicker-mzoMIlpq.js → TimePicker-D43aa4JA.js} +6 -6
- package/dist/{TimePicker-mzoMIlpq.js.map → TimePicker-D43aa4JA.js.map} +1 -1
- package/dist/{Timeline-DOojNvLG.cjs → Timeline-CFKbPpAV.cjs} +2 -2
- package/dist/{Timeline-DOojNvLG.cjs.map → Timeline-CFKbPpAV.cjs.map} +1 -1
- package/dist/{Timeline-Dg03dwTN.js → Timeline-zCHcq7Ra.js} +2 -2
- package/dist/{Timeline-Dg03dwTN.js.map → Timeline-zCHcq7Ra.js.map} +1 -1
- package/dist/{Toaster-79DvOW80.js → Toaster-BmH9V76v.js} +3 -3
- package/dist/{Toaster-79DvOW80.js.map → Toaster-BmH9V76v.js.map} +1 -1
- package/dist/{Toaster-lonArt-H.cjs → Toaster-CvtKx3FV.cjs} +2 -2
- package/dist/{Toaster-lonArt-H.cjs.map → Toaster-CvtKx3FV.cjs.map} +1 -1
- package/dist/{ToggleButtonGroup-CGNRLxjg.cjs → ToggleButtonGroup-CbKtjm8O.cjs} +2 -2
- package/dist/{ToggleButtonGroup-CGNRLxjg.cjs.map → ToggleButtonGroup-CbKtjm8O.cjs.map} +1 -1
- package/dist/{ToggleButtonGroup-K6ZcrTZT.js → ToggleButtonGroup-D3Jltv0z.js} +2 -2
- package/dist/{ToggleButtonGroup-K6ZcrTZT.js.map → ToggleButtonGroup-D3Jltv0z.js.map} +1 -1
- package/dist/{TranslatedFields-CHHtXO_n.js → TranslatedFields-Bn0cR47v.js} +5 -5
- package/dist/{TranslatedFields-CHHtXO_n.js.map → TranslatedFields-Bn0cR47v.js.map} +1 -1
- package/dist/{TranslatedFields-BYpMrYaw.cjs → TranslatedFields-U1cjZKWn.cjs} +2 -2
- package/dist/{TranslatedFields-BYpMrYaw.cjs.map → TranslatedFields-U1cjZKWn.cjs.map} +1 -1
- package/dist/{UserCard-BJFNP_nl.js → UserCard-BNKMs48t.js} +5 -5
- package/dist/{UserCard-BJFNP_nl.js.map → UserCard-BNKMs48t.js.map} +1 -1
- package/dist/{UserCard-SlkCgZS9.cjs → UserCard-D0RokNh8.cjs} +2 -2
- package/dist/{UserCard-SlkCgZS9.cjs.map → UserCard-D0RokNh8.cjs.map} +1 -1
- package/dist/{authLayoutRoute-CgSQIDD5.cjs → authLayoutRoute-23XOJ9q9.cjs} +2 -2
- package/dist/{authLayoutRoute-CgSQIDD5.cjs.map → authLayoutRoute-23XOJ9q9.cjs.map} +1 -1
- package/dist/{authLayoutRoute-CEFmEYy7.js → authLayoutRoute-BE0nGH_N.js} +2 -2
- package/dist/{authLayoutRoute-CEFmEYy7.js.map → authLayoutRoute-BE0nGH_N.js.map} +1 -1
- package/dist/chunks/icons/{62-Bfupp-0A.js → 62-9nuZO-ct.js} +9 -10
- package/dist/chunks/icons/{62-CZZzM1ev.cjs → 62-DQQ1U3IB.cjs} +1 -1
- package/dist/components/Accordion/index.cjs +1 -1
- package/dist/components/Accordion/index.js +1 -1
- package/dist/components/Alert/index.cjs +1 -1
- package/dist/components/Alert/index.js +1 -1
- package/dist/components/AuthLayout/index.cjs +1 -1
- package/dist/components/AuthLayout/index.js +1 -1
- package/dist/components/Avatar/index.cjs +1 -1
- package/dist/components/Avatar/index.js +2 -2
- package/dist/components/BottomSheet/BottomSheet.d.cts +59 -0
- package/dist/components/BottomSheet/BottomSheet.d.ts +59 -0
- package/dist/components/BottomSheet/gesture.d.cts +51 -0
- package/dist/components/BottomSheet/gesture.d.ts +51 -0
- package/dist/components/BottomSheet/index.cjs +2 -0
- package/dist/components/BottomSheet/index.cjs.map +1 -0
- package/dist/components/BottomSheet/index.d.cts +2 -0
- package/dist/components/BottomSheet/index.d.ts +2 -0
- package/dist/components/BottomSheet/index.js +6 -0
- package/dist/components/BottomSheet/index.js.map +1 -0
- package/dist/components/BottomSheet/motion.d.cts +47 -0
- package/dist/components/BottomSheet/motion.d.ts +47 -0
- 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/ChoiceCard/index.cjs +1 -1
- package/dist/components/ChoiceCard/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/DashedButton/index.cjs +1 -1
- package/dist/components/DashedButton/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/Icon/index.cjs +1 -1
- package/dist/components/Icon/index.js +1 -1
- package/dist/components/IconButton/index.cjs +1 -1
- package/dist/components/IconButton/index.js +1 -1
- package/dist/components/ImageEditor/index.cjs +1 -1
- package/dist/components/ImageEditor/index.js +1 -1
- package/dist/components/List/ListItem.d.cts +9 -1
- package/dist/components/List/ListItem.d.ts +9 -1
- package/dist/components/List/index.cjs +1 -1
- package/dist/components/List/index.d.cts +1 -1
- package/dist/components/List/index.d.ts +1 -1
- package/dist/components/List/index.js +2 -2
- package/dist/components/Loader/index.cjs +1 -1
- package/dist/components/Loader/index.js +1 -1
- package/dist/components/LocationPicker/index.cjs +1 -1
- package/dist/components/LocationPicker/index.js +1 -1
- 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/PageError/index.cjs +1 -1
- package/dist/components/PageError/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/QrCode/index.cjs +1 -1
- package/dist/components/QrCode/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/Sidebar.d.cts +40 -4
- package/dist/components/Sidebar/Sidebar.d.ts +40 -4
- package/dist/components/Sidebar/index.cjs +1 -1
- package/dist/components/Sidebar/index.d.cts +2 -1
- package/dist/components/Sidebar/index.d.ts +2 -1
- package/dist/components/Sidebar/index.js +5 -4
- package/dist/components/Slider/index.cjs +1 -1
- package/dist/components/Slider/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/SwatchPicker/index.cjs +1 -1
- package/dist/components/SwatchPicker/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/Timeline/index.cjs +1 -1
- package/dist/components/Timeline/index.js +1 -1
- package/dist/components/Toast/index.cjs +1 -1
- package/dist/components/Toast/index.js +1 -1
- package/dist/components/ToggleButton/index.cjs +1 -1
- package/dist/components/ToggleButton/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/auth.cjs +1 -1
- package/dist/entries/auth.js +2 -2
- package/dist/entries/components.cjs +1 -1
- package/dist/entries/components.js +192 -189
- 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/icons.cjs +1 -1
- package/dist/entries/icons.js +1 -1
- package/dist/entries/theme.cjs +1 -1
- package/dist/entries/theme.js +1 -1
- package/dist/i18n/messages.d.cts +6 -0
- package/dist/i18n/messages.d.ts +6 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +208 -205
- package/dist/index.js.map +1 -1
- package/dist/messages-C2DUaZkS.cjs +36 -0
- package/dist/messages-C2DUaZkS.cjs.map +1 -0
- package/dist/{messages-DeQuvGln.js → messages-DWL0ZaKa.js} +36 -15
- package/dist/messages-DWL0ZaKa.js.map +1 -0
- package/dist/useHomeTo-Ao53ZjWz.cjs +2 -0
- package/dist/useHomeTo-Ao53ZjWz.cjs.map +1 -0
- package/dist/useHomeTo-DG69efNE.js +10 -0
- package/dist/useHomeTo-DG69efNE.js.map +1 -0
- package/dist/{useOptionMenu-6ZffgbYG.cjs → useOptionMenu-B9zQfGTN.cjs} +2 -2
- package/dist/{useOptionMenu-6ZffgbYG.cjs.map → useOptionMenu-B9zQfGTN.cjs.map} +1 -1
- package/dist/{useOptionMenu-CxM6FHXL.js → useOptionMenu-C8SEMVFV.js} +6 -6
- package/dist/{useOptionMenu-CxM6FHXL.js.map → useOptionMenu-C8SEMVFV.js.map} +1 -1
- package/package.json +1 -1
- package/dist/Icon-B7DJn8Tw.js.map +0 -1
- package/dist/Icon-CBg21lKA.cjs +0 -2
- package/dist/Icon-CBg21lKA.cjs.map +0 -1
- package/dist/ListItem-CguNjf-u.cjs +0 -2
- package/dist/ListItem-CguNjf-u.cjs.map +0 -1
- package/dist/ListItem-Ezmdk7q-.js +0 -76
- package/dist/ListItem-Ezmdk7q-.js.map +0 -1
- package/dist/Sidebar-CLr-DyQ_.js +0 -522
- package/dist/Sidebar-CLr-DyQ_.js.map +0 -1
- package/dist/Sidebar-CM-jZfj5.cjs +0 -2
- package/dist/Sidebar-CM-jZfj5.cjs.map +0 -1
- package/dist/messages-DeQuvGln.js.map +0 -1
- package/dist/messages-dL9MkVze.cjs +0 -36
- package/dist/messages-dL9MkVze.cjs.map +0 -1
- package/dist/useHomeTo-BLSvhJd5.js +0 -25
- package/dist/useHomeTo-BLSvhJd5.js.map +0 -1
- package/dist/useHomeTo-cXCg1tf0.cjs +0 -2
- package/dist/useHomeTo-cXCg1tf0.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthGuard-Ck31lvBA.js","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab — written when the\n// guard turns a visitor away and when a reader finds a safe param in the URL (a reloaded or shared login\n// link). Memory only — a path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/**\n * A safe param a reader found in the login URL becomes the tab's target (the fresher intent), so the next\n * step of a sign-in — which drops the query string — still finds it. `?redirect=/` means home: it replaces\n * an older target by forgetting it.\n */\nconst rememberFromUrl = (target: string) => {\n if (target === '/') {\n if (!signingOut) remembered = null\n } else rememberAuthRedirect(target)\n}\n\n/**\n * The target for a search string — its param, else the remembered one — or `null` when there's none. With\n * `remember`, a safe param is also remembered for the tab (see `rememberFromUrl`).\n */\nconst findAuthRedirect = (searchStr: string, queryKey: string, remember: boolean) => {\n const fromParam = safe(paramOf(searchStr, queryKey))\n if (fromParam) {\n if (remember) rememberFromUrl(fromParam)\n return fromParam\n }\n return isBrowser() ? safe(remembered) : null\n}\n\n/**\n * @internal The target for a search string: its param, else the remembered one, else `fallback`. Reads\n * only — `authLayoutRoute` bounces an already signed-in visitor with it, and that bounce has no later\n * sign-in step to remember anything for (a target left in memory while signed in would come back on the\n * next sign-in).\n */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey, false) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). A safe param it finds is remembered for the tab, so a later step of the\n * sign-in that drops the query string still gets it (`?redirect=/` forgets an older target instead).\n * Unsafe params are ignored and never overwrite a remembered target. The param name follows\n * `config.keys.redirectQueryKey` once the guard, the shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n const searchStr = typeof window === 'undefined' ? '' : window.location.search\n return findAuthRedirect(searchStr, settings.queryKey, true) ?? fallback\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). A safe param it finds is remembered for the tab (a reloaded or shared login link then\n * survives a multi-step sign-in; `?redirect=/` forgets an older target instead). It never spends the\n * target; that's forgotten once `AuthGuard` renders signed-in content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) {\n // a new param: remember it for the tab (idempotent, so the StrictMode double render is harmless)\n if (fromParam !== found.current) rememberFromUrl(fromParam)\n found.current = fromParam\n } else if (found.current === null) found.current = findAuthRedirect('', queryKey, false)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport {\n authRedirectConsumed,\n clearAuthRedirect,\n configureAuthRedirect,\n rememberAuthRedirect,\n} from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s) — and turning a visitor away from such a page forgets an\n * older remembered target, so it can't come back on the next sign-in. Once it renders signed-in content,\n * the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n // the turn-away is authoritative: from a page not worth remembering (`/`), an older target mustn't\n // come back on the next sign-in\n if (target.current === null) clearAuthRedirect()\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","rememberFromUrl","target","findAuthRedirect","queryKey","remember","fromParam","resolveAuthRedirect","fallback","rememberAuthRedirect","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","s","found","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthGuard-D6_sTASu.js","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab — written when the\n// guard turns a visitor away and when a reader finds a safe param in the URL (a reloaded or shared login\n// link). Memory only — a path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/**\n * A safe param a reader found in the login URL becomes the tab's target (the fresher intent), so the next\n * step of a sign-in — which drops the query string — still finds it. `?redirect=/` means home: it replaces\n * an older target by forgetting it.\n */\nconst rememberFromUrl = (target: string) => {\n if (target === '/') {\n if (!signingOut) remembered = null\n } else rememberAuthRedirect(target)\n}\n\n/**\n * The target for a search string — its param, else the remembered one — or `null` when there's none. With\n * `remember`, a safe param is also remembered for the tab (see `rememberFromUrl`).\n */\nconst findAuthRedirect = (searchStr: string, queryKey: string, remember: boolean) => {\n const fromParam = safe(paramOf(searchStr, queryKey))\n if (fromParam) {\n if (remember) rememberFromUrl(fromParam)\n return fromParam\n }\n return isBrowser() ? safe(remembered) : null\n}\n\n/**\n * @internal The target for a search string: its param, else the remembered one, else `fallback`. Reads\n * only — `authLayoutRoute` bounces an already signed-in visitor with it, and that bounce has no later\n * sign-in step to remember anything for (a target left in memory while signed in would come back on the\n * next sign-in).\n */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey, false) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). A safe param it finds is remembered for the tab, so a later step of the\n * sign-in that drops the query string still gets it (`?redirect=/` forgets an older target instead).\n * Unsafe params are ignored and never overwrite a remembered target. The param name follows\n * `config.keys.redirectQueryKey` once the guard, the shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n const searchStr = typeof window === 'undefined' ? '' : window.location.search\n return findAuthRedirect(searchStr, settings.queryKey, true) ?? fallback\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). A safe param it finds is remembered for the tab (a reloaded or shared login link then\n * survives a multi-step sign-in; `?redirect=/` forgets an older target instead). It never spends the\n * target; that's forgotten once `AuthGuard` renders signed-in content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) {\n // a new param: remember it for the tab (idempotent, so the StrictMode double render is harmless)\n if (fromParam !== found.current) rememberFromUrl(fromParam)\n found.current = fromParam\n } else if (found.current === null) found.current = findAuthRedirect('', queryKey, false)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport {\n authRedirectConsumed,\n clearAuthRedirect,\n configureAuthRedirect,\n rememberAuthRedirect,\n} from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s) — and turning a visitor away from such a page forgets an\n * older remembered target, so it can't come back on the next sign-in. Once it renders signed-in content,\n * the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n // the turn-away is authoritative: from a page not worth remembering (`/`), an older target mustn't\n // come back on the next sign-in\n if (target.current === null) clearAuthRedirect()\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","rememberFromUrl","target","findAuthRedirect","queryKey","remember","fromParam","resolveAuthRedirect","fallback","rememberAuthRedirect","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","s","found","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const g=require("react/jsx-runtime"),h=require("@tanstack/react-router"),o=require("react"),m=require("./ConfigProvider-
|
|
2
|
-
//# sourceMappingURL=AuthGuard-
|
|
1
|
+
"use strict";const g=require("react/jsx-runtime"),h=require("@tanstack/react-router"),o=require("react"),m=require("./ConfigProvider-DPk0aHDG.cjs"),O=2048;let s=null,a=!1;const l={queryKey:m.DEFAULT_REDIRECT_QUERY_KEY,loginPath:"/login",isAuthPath:null};function y(e){Object.assign(l,e)}const p=()=>typeof window<"u",P=()=>typeof window>"u"?"http://localhost":window.location.origin,U=(e,t)=>{const u=t.length>1?t.replace(/\/+$/,""):t;return e===u||e.startsWith(`${u}/`)};function _(e,{loginPath:t,isAuthPath:u,origin:r=P()}){if(typeof e!="string"||e.length===0||e.length>O||!e.startsWith("/")||e.startsWith("//")||e.startsWith("/\\"))return null;let n;try{n=new URL(e,r)}catch{return null}if(n.origin!==r||n.pathname.startsWith("//")||U(n.pathname,t))return null;try{if(u!=null&&u(n.pathname))return null}catch{}return`${n.pathname}${n.search}${n.hash}`}const d=e=>_(e,{loginPath:l.loginPath,isAuthPath:l.isAuthPath}),q=(e,t)=>{try{return new URLSearchParams(e).get(t)}catch{return null}},E=e=>{e==="/"?a||(s=null):S(e)},A=(e,t,u)=>{const r=d(q(e,t));return r?(u&&E(r),r):p()?d(s):null};function b(e,t="/",u=l.queryKey){return A(e,u,!1)??t}function S(e){if(a||!p())return null;const t=d(e);return!t||t==="/"?null:(s=t,t)}function W(){s=null,a=p()}function j(){a=!1}function C(){s=null,a=!1}function L(e="/"){const t=typeof window>"u"?"":window.location.search;return A(t,l.queryKey,!0)??e}function x(e="/"){const t=m.useRedirectQueryKey();y({queryKey:t});const u=h.useRouter(),r=o.useRef(null);r.current===null&&(r.current=u.state.location.pathname);const n=o.useRef(null),R=h.useRouterState({select:f=>(f.location.pathname===r.current&&(n.current=q(f.location.searchStr,t)),n.current)}),c=o.useRef(null),i=d(R);return i?(i!==c.current&&E(i),c.current=i):c.current===null&&(c.current=A("",t,!1)),c.current??e}function $(){s=null}const D=({isAuthenticated:e,redirectTo:t="/login",children:u})=>{const r=typeof e=="function"?e():e,n=m.useRedirectQueryKey(),R=h.useRouter();y({queryKey:n,loginPath:t});const c=o.useRef(void 0);if(r)c.current=void 0;else if(c.current===void 0){const{pathname:f,searchStr:K,hash:w}=R.state.location;c.current=S(`${f}${K}${w?`#${w}`:""}`),c.current===null&&$()}const i=o.useMemo(()=>r?null:g.jsx(h.Navigate,{to:t,search:c.current?{[n]:c.current}:{},replace:!0}),[r,t,n]);return o.useEffect(()=>{r&&C()},[r]),r?g.jsx(g.Fragment,{children:u}):i};exports.AuthGuard=D;exports.beginSignOut=W;exports.clearAuthRedirect=$;exports.configureAuthRedirect=y;exports.endSignOut=j;exports.getAuthRedirect=L;exports.resolveAuthRedirect=b;exports.useAuthRedirect=x;
|
|
2
|
+
//# sourceMappingURL=AuthGuard-DM1nDTE5.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthGuard-C2eA3mJA.cjs","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab — written when the\n// guard turns a visitor away and when a reader finds a safe param in the URL (a reloaded or shared login\n// link). Memory only — a path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/**\n * A safe param a reader found in the login URL becomes the tab's target (the fresher intent), so the next\n * step of a sign-in — which drops the query string — still finds it. `?redirect=/` means home: it replaces\n * an older target by forgetting it.\n */\nconst rememberFromUrl = (target: string) => {\n if (target === '/') {\n if (!signingOut) remembered = null\n } else rememberAuthRedirect(target)\n}\n\n/**\n * The target for a search string — its param, else the remembered one — or `null` when there's none. With\n * `remember`, a safe param is also remembered for the tab (see `rememberFromUrl`).\n */\nconst findAuthRedirect = (searchStr: string, queryKey: string, remember: boolean) => {\n const fromParam = safe(paramOf(searchStr, queryKey))\n if (fromParam) {\n if (remember) rememberFromUrl(fromParam)\n return fromParam\n }\n return isBrowser() ? safe(remembered) : null\n}\n\n/**\n * @internal The target for a search string: its param, else the remembered one, else `fallback`. Reads\n * only — `authLayoutRoute` bounces an already signed-in visitor with it, and that bounce has no later\n * sign-in step to remember anything for (a target left in memory while signed in would come back on the\n * next sign-in).\n */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey, false) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). A safe param it finds is remembered for the tab, so a later step of the\n * sign-in that drops the query string still gets it (`?redirect=/` forgets an older target instead).\n * Unsafe params are ignored and never overwrite a remembered target. The param name follows\n * `config.keys.redirectQueryKey` once the guard, the shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n const searchStr = typeof window === 'undefined' ? '' : window.location.search\n return findAuthRedirect(searchStr, settings.queryKey, true) ?? fallback\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). A safe param it finds is remembered for the tab (a reloaded or shared login link then\n * survives a multi-step sign-in; `?redirect=/` forgets an older target instead). It never spends the\n * target; that's forgotten once `AuthGuard` renders signed-in content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) {\n // a new param: remember it for the tab (idempotent, so the StrictMode double render is harmless)\n if (fromParam !== found.current) rememberFromUrl(fromParam)\n found.current = fromParam\n } else if (found.current === null) found.current = findAuthRedirect('', queryKey, false)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport {\n authRedirectConsumed,\n clearAuthRedirect,\n configureAuthRedirect,\n rememberAuthRedirect,\n} from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s) — and turning a visitor away from such a page forgets an\n * older remembered target, so it can't come back on the next sign-in. Once it renders signed-in content,\n * the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n // the turn-away is authoritative: from a page not worth remembering (`/`), an older target mustn't\n // come back on the next sign-in\n if (target.current === null) clearAuthRedirect()\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","rememberFromUrl","target","findAuthRedirect","queryKey","remember","fromParam","resolveAuthRedirect","fallback","rememberAuthRedirect","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","s","found","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthGuard-DM1nDTE5.cjs","sources":["../src/auth/authRedirect.ts","../src/auth/AuthGuard.tsx"],"sourcesContent":["// Return-after-sign-in: where `AuthGuard` sent a signed-out visitor away from, read back once they've\n// signed in. The target travels in the login URL (`?redirect=…`) and, for a multi-step sign-in that moves\n// between auth routes and drops the query string, in a module-level slot for this tab — written when the\n// guard turns a visitor away and when a reader finds a safe param in the URL (a reloaded or shared login\n// link). Memory only — a path can carry record ids, so it never goes to localStorage / sessionStorage.\nimport { useRouter, useRouterState } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { DEFAULT_REDIRECT_QUERY_KEY, useRedirectQueryKey } from '../theme/ConfigProvider'\n\n/** The longest target accepted (characters) — anything longer is treated as crafted. */\nexport const AUTH_REDIRECT_MAX_LENGTH = 2048\n\n/** What the safety check needs to know about the app's sign-in pages. */\nexport interface AuthRedirectContext {\n /** The sign-in page — the target may not be it, or a step under it (`/login/mfa`). */\n loginPath: string\n /** Whether a path belongs to a public auth page (under `authRouteId`) — registered by `AdminRoot`. */\n isAuthPath?: ((pathname: string) => boolean) | null\n /** The origin a target must stay on. Defaults to `window.location.origin`. */\n origin?: string\n}\n\n// The tab's state. `settings` is what the guard / shell last told us (the configured param name, the\n// login path, the auth-page matcher), so `getAuthRedirect` works outside React with no arguments.\nlet remembered: string | null = null\nlet signingOut = false\nconst settings: Required<Omit<AuthRedirectContext, 'origin'>> & { queryKey: string } = {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n}\n\n/** @internal Update what the module knows about the app (called by `AuthGuard` / `AdminRoot` / the hook). */\nexport function configureAuthRedirect(next: Partial<typeof settings>) {\n Object.assign(settings, next)\n}\n\n// the memory slot is per browser tab — on a server it would be shared between visitors, so it's off there\nconst isBrowser = () => typeof window !== 'undefined'\n\nconst currentOrigin = () =>\n typeof window === 'undefined' ? 'http://localhost' : window.location.origin\n\nconst isUnder = (pathname: string, base: string) => {\n const b = base.length > 1 ? base.replace(/\\/+$/, '') : base\n return pathname === b || pathname.startsWith(`${b}/`)\n}\n\n/**\n * The target, normalized to `pathname + search + hash`, when it's safe to navigate to — else `null`.\n * Safe = a string of at most `AUTH_REDIRECT_MAX_LENGTH` characters, starting with a single `/`, that\n * resolves to the same origin (rejects `https://evil.example`, `//evil.example`, `/\\evil.example`,\n * `javascript:…`), and isn't the login path, a step under it, or a public auth page.\n */\nexport function safeAuthRedirect(\n value: unknown,\n { loginPath, isAuthPath, origin = currentOrigin() }: AuthRedirectContext,\n): string | null {\n if (typeof value !== 'string' || value.length === 0 || value.length > AUTH_REDIRECT_MAX_LENGTH)\n return null\n if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\\\')) return null\n let url: URL\n try {\n url = new URL(value, origin)\n } catch {\n return null\n }\n // the parser drops tabs / newlines, so `/\\t/evil.example` only shows its real origin here\n if (url.origin !== origin) return null\n // …and collapses `/./`, `%2e` and `\\` — `/.//evil.example` normalizes to `//evil.example`\n if (url.pathname.startsWith('//')) return null\n if (isUnder(url.pathname, loginPath)) return null\n try {\n if (isAuthPath?.(url.pathname)) return null\n } catch {\n // an unmatchable path isn't an auth page\n }\n return `${url.pathname}${url.search}${url.hash}`\n}\n\n/** The safety check with the module's current settings. */\nconst safe = (value: unknown) =>\n safeAuthRedirect(value, { loginPath: settings.loginPath, isAuthPath: settings.isAuthPath })\n\n/** Read a param out of a raw search string (`?a=1&b=2`). */\nconst paramOf = (searchStr: string, key: string) => {\n try {\n return new URLSearchParams(searchStr).get(key)\n } catch {\n return null\n }\n}\n\n/**\n * A safe param a reader found in the login URL becomes the tab's target (the fresher intent), so the next\n * step of a sign-in — which drops the query string — still finds it. `?redirect=/` means home: it replaces\n * an older target by forgetting it.\n */\nconst rememberFromUrl = (target: string) => {\n if (target === '/') {\n if (!signingOut) remembered = null\n } else rememberAuthRedirect(target)\n}\n\n/**\n * The target for a search string — its param, else the remembered one — or `null` when there's none. With\n * `remember`, a safe param is also remembered for the tab (see `rememberFromUrl`).\n */\nconst findAuthRedirect = (searchStr: string, queryKey: string, remember: boolean) => {\n const fromParam = safe(paramOf(searchStr, queryKey))\n if (fromParam) {\n if (remember) rememberFromUrl(fromParam)\n return fromParam\n }\n return isBrowser() ? safe(remembered) : null\n}\n\n/**\n * @internal The target for a search string: its param, else the remembered one, else `fallback`. Reads\n * only — `authLayoutRoute` bounces an already signed-in visitor with it, and that bounce has no later\n * sign-in step to remember anything for (a target left in memory while signed in would come back on the\n * next sign-in).\n */\nexport function resolveAuthRedirect(\n searchStr: string,\n fallback = '/',\n queryKey = settings.queryKey,\n) {\n return findAuthRedirect(searchStr, queryKey, false) ?? fallback\n}\n\n/**\n * @internal Remember a target for this tab — returns it (normalized) when it's worth remembering, `null`\n * otherwise (unsafe, `/`, the login path, or an explicit Sign Out is under way).\n */\nexport function rememberAuthRedirect(target: string): string | null {\n if (signingOut || !isBrowser()) return null\n const value = safe(target)\n if (!value || value === '/') return null\n remembered = value\n return value\n}\n\n/**\n * @internal An explicit Sign Out: forget the target and remember nothing until `endSignOut` (once the\n * navigation to the login page has settled) or the next sign-in.\n */\nexport function beginSignOut() {\n remembered = null\n signingOut = isBrowser()\n}\n\n/** @internal The Sign Out navigation settled — later guard redirects remember their page again. */\nexport function endSignOut() {\n signingOut = false\n}\n\n/** @internal Signed in (the guard rendered its content): the target is spent, Sign Out is over. */\nexport function authRedirectConsumed() {\n remembered = null\n signingOut = false\n}\n\n/**\n * Where to go after a successful sign-in, outside React (a route `beforeLoad`, a mutation's `onSuccess`):\n * the `?redirect=` param of `window.location` if it's safe, else the target remembered in this tab, else\n * `fallback` (default `'/'`). A safe param it finds is remembered for the tab, so a later step of the\n * sign-in that drops the query string still gets it (`?redirect=/` forgets an older target instead).\n * Unsafe params are ignored and never overwrite a remembered target. The param name follows\n * `config.keys.redirectQueryKey` once the guard, the shell or `useAuthRedirect` has rendered.\n */\nexport function getAuthRedirect(fallback = '/'): string {\n const searchStr = typeof window === 'undefined' ? '' : window.location.search\n return findAuthRedirect(searchStr, settings.queryKey, true) ?? fallback\n}\n\n/**\n * Where to go after a successful sign-in: the `?redirect=` param of the page this component is mounted on\n * (read from the router's location) if it's safe, else the target remembered in this tab, else `fallback`\n * (default `'/'`). A safe param it finds is remembered for the tab (a reloaded or shared login link then\n * survives a multi-step sign-in; `?redirect=/` forgets an older target instead). It never spends the\n * target; that's forgotten once `AuthGuard` renders signed-in content (or `clearAuthRedirect`).\n *\n * **Stable for the component's life:** once it has found a target it keeps returning it, and it listens\n * only to the `?redirect=` of the page it was mounted on. A `<Navigate>` to the target moves the router's\n * location there (no param any more) while the login page can still be mounted — e.g. a code-split route\n * whose chunk is loading — and a value that changed then would make the `<Navigate>` navigate again, to\n * the fallback; a re-render alone would too (TanStack's `<Navigate>` navigates on new props), so location\n * changes elsewhere don't re-render it. A new safe param on its own page (arriving after mount) still wins.\n *\n * @example\n * const to = useAuthRedirect('/')\n * if (status === 'authenticated') return <Navigate to={to} replace />\n */\nexport function useAuthRedirect(fallback = '/'): string {\n const queryKey = useRedirectQueryKey()\n configureAuthRedirect({ queryKey })\n const router = useRouter()\n // the page this component was mounted on — only its own URL is listened to\n const page = useRef<string | null>(null)\n if (page.current === null) page.current = router.state.location.pathname\n // the param of that page, held once the router has moved on — so the navigation to the target (or a\n // guard redirecting away from it) doesn't re-render this component, and its `<Navigate>` fires once\n const heard = useRef<string | null>(null)\n const param = useRouterState({\n select: (s) => {\n if (s.location.pathname === page.current)\n heard.current = paramOf(s.location.searchStr, queryKey)\n return heard.current\n },\n })\n const found = useRef<string | null>(null)\n const fromParam = safe(param)\n if (fromParam) {\n // a new param: remember it for the tab (idempotent, so the StrictMode double render is harmless)\n if (fromParam !== found.current) rememberFromUrl(fromParam)\n found.current = fromParam\n } else if (found.current === null) found.current = findAuthRedirect('', queryKey, false)\n return found.current ?? fallback\n}\n\n/**\n * Forget the remembered target. `AuthGuard` already does this once it renders signed-in content, so a\n * later sign-in in the same tab doesn't reuse it — call it yourself only when you navigate elsewhere.\n */\nexport function clearAuthRedirect(): void {\n remembered = null\n}\n\n/** @internal Test-only: back to a fresh tab. */\nexport function resetAuthRedirect() {\n remembered = null\n signingOut = false\n Object.assign(settings, {\n queryKey: DEFAULT_REDIRECT_QUERY_KEY,\n loginPath: '/login',\n isAuthPath: null,\n })\n}\n","import { Navigate, useRouter, type LinkProps } from '@tanstack/react-router'\nimport { useEffect, useMemo, useRef, type ReactNode } from 'react'\nimport { useRedirectQueryKey } from '../theme/ConfigProvider'\nimport {\n authRedirectConsumed,\n clearAuthRedirect,\n configureAuthRedirect,\n rememberAuthRedirect,\n} from './authRedirect'\n\nexport interface AuthGuardProps {\n /** Session check — a boolean, or a function that returns one (evaluated on render). */\n isAuthenticated: boolean | (() => boolean)\n /** Where to send an unauthenticated visitor. Defaults to `'/login'`. */\n redirectTo?: string\n /** The protected content, rendered only when authenticated. */\n children: ReactNode\n}\n\n/**\n * Component-level auth guard: renders `children` only when authenticated, otherwise redirects to\n * `redirectTo` via `<Navigate replace>` (so Back from the login page doesn't bounce off the guard).\n *\n * The redirect **remembers the page**: it adds `?redirect=<path + search + hash>` to the login URL (the\n * param name follows `config.keys.redirectQueryKey`) and keeps the same target in memory for this tab, so\n * a multi-step sign-in that drops the query string still knows it. Read it back after sign-in with\n * `useAuthRedirect` / `getAuthRedirect`. Nothing is remembered from `/`, from the login path itself, or\n * during an explicit Sign Out (`AdminRoot`'s) — and turning a visitor away from such a page forgets an\n * older remembered target, so it can't come back on the next sign-in. Once it renders signed-in content,\n * the target is forgotten.\n *\n * Requires a `@tanstack/react-router` context (it renders `<Navigate>`), so use it inside a routed\n * tree. `redirectTo` is a plain string — the library can't know the app's typed route tree, so it's\n * cast loosely to the router's `to` type.\n *\n * @example\n * <AuthGuard isAuthenticated={session.isAuthenticated} redirectTo=\"/login\">\n * <Dashboard />\n * </AuthGuard>\n */\nexport const AuthGuard = ({ isAuthenticated, redirectTo = '/login', children }: AuthGuardProps) => {\n const ok = typeof isAuthenticated === 'function' ? isAuthenticated() : isAuthenticated\n const queryKey = useRedirectQueryKey()\n const router = useRouter()\n configureAuthRedirect({ queryKey, loginPath: redirectTo })\n // The target is taken once, when the guard first turns the visitor away, and read without subscribing:\n // the router moves its location to the login URL before the login page mounts, so a later render here\n // would read that instead (and a `<Navigate>` whose props change navigates again).\n const target = useRef<string | null | undefined>(undefined)\n if (ok) target.current = undefined\n else if (target.current === undefined) {\n const { pathname, searchStr, hash } = router.state.location\n target.current = rememberAuthRedirect(`${pathname}${searchStr}${hash ? `#${hash}` : ''}`)\n // the turn-away is authoritative: from a page not worth remembering (`/`), an older target mustn't\n // come back on the next sign-in\n if (target.current === null) clearAuthRedirect()\n }\n const redirect = useMemo(\n () =>\n ok ? null : (\n <Navigate\n to={redirectTo as LinkProps['to']}\n search={(target.current ? { [queryKey]: target.current } : {}) as LinkProps['search']}\n replace\n />\n ),\n [ok, redirectTo, queryKey],\n )\n\n // signed in: a remembered target is spent (and a Sign Out is over) — idempotent, so StrictMode is fine\n useEffect(() => {\n if (ok) authRedirectConsumed()\n }, [ok])\n\n return ok ? <>{children}</> : redirect\n}\n"],"names":["AUTH_REDIRECT_MAX_LENGTH","remembered","signingOut","settings","DEFAULT_REDIRECT_QUERY_KEY","configureAuthRedirect","next","isBrowser","currentOrigin","isUnder","pathname","base","b","safeAuthRedirect","value","loginPath","isAuthPath","origin","url","safe","paramOf","searchStr","key","rememberFromUrl","target","findAuthRedirect","queryKey","remember","fromParam","resolveAuthRedirect","fallback","rememberAuthRedirect","beginSignOut","endSignOut","authRedirectConsumed","getAuthRedirect","useAuthRedirect","useRedirectQueryKey","router","useRouter","page","useRef","heard","param","useRouterState","s","found","clearAuthRedirect","AuthGuard","isAuthenticated","redirectTo","children","ok","hash","redirect","useMemo","jsx","Navigate","useEffect","Fragment"],"mappings":"oJAUaA,EAA2B,KAcxC,IAAIC,EAA4B,KAC5BC,EAAa,GACjB,MAAMC,EAAiF,CACrF,SAAUC,EAAAA,2BACV,UAAW,SACX,WAAY,IACd,EAGO,SAASC,EAAsBC,EAAgC,CACpE,OAAO,OAAOH,EAAUG,CAAI,CAC9B,CAGA,MAAMC,EAAY,IAAM,OAAO,OAAW,IAEpCC,EAAgB,IACpB,OAAO,OAAW,IAAc,mBAAqB,OAAO,SAAS,OAEjEC,EAAU,CAACC,EAAkBC,IAAiB,CAClD,MAAMC,EAAID,EAAK,OAAS,EAAIA,EAAK,QAAQ,OAAQ,EAAE,EAAIA,EACvD,OAAOD,IAAaE,GAAKF,EAAS,WAAW,GAAGE,CAAC,GAAG,CACtD,EAQO,SAASC,EACdC,EACA,CAAE,UAAAC,EAAW,WAAAC,EAAY,OAAAC,EAAST,EAAA,GACnB,CAGf,GAFI,OAAOM,GAAU,UAAYA,EAAM,SAAW,GAAKA,EAAM,OAASd,GAElE,CAACc,EAAM,WAAW,GAAG,GAAKA,EAAM,WAAW,IAAI,GAAKA,EAAM,WAAW,KAAK,EAAG,OAAO,KACxF,IAAII,EACJ,GAAI,CACFA,EAAM,IAAI,IAAIJ,EAAOG,CAAM,CAC7B,MAAQ,CACN,OAAO,IACT,CAKA,GAHIC,EAAI,SAAWD,GAEfC,EAAI,SAAS,WAAW,IAAI,GAC5BT,EAAQS,EAAI,SAAUH,CAAS,EAAG,OAAO,KAC7C,GAAI,CACF,GAAIC,GAAA,MAAAA,EAAaE,EAAI,UAAW,OAAO,IACzC,MAAQ,CAER,CACA,MAAO,GAAGA,EAAI,QAAQ,GAAGA,EAAI,MAAM,GAAGA,EAAI,IAAI,EAChD,CAGA,MAAMC,EAAQL,GACZD,EAAiBC,EAAO,CAAE,UAAWX,EAAS,UAAW,WAAYA,EAAS,UAAA,CAAY,EAGtFiB,EAAU,CAACC,EAAmBC,IAAgB,CAClD,GAAI,CACF,OAAO,IAAI,gBAAgBD,CAAS,EAAE,IAAIC,CAAG,CAC/C,MAAQ,CACN,OAAO,IACT,CACF,EAOMC,EAAmBC,GAAmB,CACtCA,IAAW,IACRtB,IAAYD,EAAa,QACJuB,CAAM,CACpC,EAMMC,EAAmB,CAACJ,EAAmBK,EAAkBC,IAAsB,CACnF,MAAMC,EAAYT,EAAKC,EAAQC,EAAWK,CAAQ,CAAC,EACnD,OAAIE,GACED,KAA0BC,CAAS,EAChCA,GAEFrB,EAAA,EAAcY,EAAKlB,CAAU,EAAI,IAC1C,EAQO,SAAS4B,EACdR,EACAS,EAAW,IACXJ,EAAWvB,EAAS,SACpB,CACA,OAAOsB,EAAiBJ,EAAWK,EAAU,EAAK,GAAKI,CACzD,CAMO,SAASC,EAAqBP,EAA+B,CAClE,GAAItB,GAAc,CAACK,EAAA,EAAa,OAAO,KACvC,MAAMO,EAAQK,EAAKK,CAAM,EACzB,MAAI,CAACV,GAASA,IAAU,IAAY,MACpCb,EAAaa,EACNA,EACT,CAMO,SAASkB,GAAe,CAC7B/B,EAAa,KACbC,EAAaK,EAAA,CACf,CAGO,SAAS0B,GAAa,CAC3B/B,EAAa,EACf,CAGO,SAASgC,GAAuB,CACrCjC,EAAa,KACbC,EAAa,EACf,CAUO,SAASiC,EAAgBL,EAAW,IAAa,CACtD,MAAMT,EAAY,OAAO,OAAW,IAAc,GAAK,OAAO,SAAS,OACvE,OAAOI,EAAiBJ,EAAWlB,EAAS,SAAU,EAAI,GAAK2B,CACjE,CAoBO,SAASM,EAAgBN,EAAW,IAAa,CACtD,MAAMJ,EAAWW,EAAAA,oBAAA,EACjBhC,EAAsB,CAAE,SAAAqB,EAAU,EAClC,MAAMY,EAASC,EAAAA,UAAA,EAETC,EAAOC,EAAAA,OAAsB,IAAI,EACnCD,EAAK,UAAY,SAAW,QAAUF,EAAO,MAAM,SAAS,UAGhE,MAAMI,EAAQD,EAAAA,OAAsB,IAAI,EAClCE,EAAQC,EAAAA,eAAe,CAC3B,OAASC,IACHA,EAAE,SAAS,WAAaL,EAAK,UAC/BE,EAAM,QAAUtB,EAAQyB,EAAE,SAAS,UAAWnB,CAAQ,GACjDgB,EAAM,QACf,CACD,EACKI,EAAQL,EAAAA,OAAsB,IAAI,EAClCb,EAAYT,EAAKwB,CAAK,EAC5B,OAAIf,GAEEA,IAAckB,EAAM,SAASvB,EAAgBK,CAAS,EAC1DkB,EAAM,QAAUlB,GACPkB,EAAM,UAAY,SAAY,QAAUrB,EAAiB,GAAIC,EAAU,EAAK,GAChFoB,EAAM,SAAWhB,CAC1B,CAMO,SAASiB,GAA0B,CACxC9C,EAAa,IACf,CC3LO,MAAM+C,EAAY,CAAC,CAAE,gBAAAC,EAAiB,WAAAC,EAAa,SAAU,SAAAC,KAA+B,CACjG,MAAMC,EAAK,OAAOH,GAAoB,WAAaA,IAAoBA,EACjEvB,EAAWW,EAAAA,oBAAA,EACXC,EAASC,EAAAA,UAAA,EACflC,EAAsB,CAAE,SAAAqB,EAAU,UAAWwB,CAAA,CAAY,EAIzD,MAAM1B,EAASiB,EAAAA,OAAkC,MAAS,EAC1D,GAAIW,IAAW,QAAU,eAChB5B,EAAO,UAAY,OAAW,CACrC,KAAM,CAAE,SAAAd,EAAU,UAAAW,EAAW,KAAAgC,CAAA,EAASf,EAAO,MAAM,SACnDd,EAAO,QAAUO,EAAqB,GAAGrB,CAAQ,GAAGW,CAAS,GAAGgC,EAAO,IAAIA,CAAI,GAAK,EAAE,EAAE,EAGpF7B,EAAO,UAAY,MAAMuB,EAAA,CAC/B,CACA,MAAMO,EAAWC,EAAAA,QACf,IACEH,EAAK,KACHI,EAAAA,IAACC,EAAAA,SAAA,CACC,GAAIP,EACJ,OAAS1B,EAAO,QAAU,CAAE,CAACE,CAAQ,EAAGF,EAAO,OAAA,EAAY,CAAA,EAC3D,QAAO,EAAA,CAAA,EAGb,CAAC4B,EAAIF,EAAYxB,CAAQ,CAAA,EAI3BgC,OAAAA,EAAAA,UAAU,IAAM,CACVN,GAAIlB,EAAA,CACV,EAAG,CAACkB,CAAE,CAAC,EAEAA,EAAKI,EAAAA,IAAAG,EAAAA,SAAA,CAAG,SAAAR,CAAA,CAAS,EAAMG,CAChC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as n, jsx as a } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as g } from "react";
|
|
3
3
|
import { clsx as y } from "clsx";
|
|
4
|
-
import { A as f } from "./Avatar-
|
|
4
|
+
import { A as f } from "./Avatar-C4qgzth2.js";
|
|
5
5
|
import { T as u } from "./Typography-ChSuxgkc.js";
|
|
6
6
|
const p = "_authLayout_1vumg_3", N = "_logo_1vumg_20", L = "_card_1vumg_36", A = "_icon_1vumg_50", x = "_header_1vumg_55", b = "_body_1vumg_62", j = "_footer_1vumg_68", o = {
|
|
7
7
|
authLayout: p,
|
|
@@ -40,4 +40,4 @@ const p = "_authLayout_1vumg_3", N = "_logo_1vumg_20", L = "_card_1vumg_36", A =
|
|
|
40
40
|
export {
|
|
41
41
|
B as A
|
|
42
42
|
};
|
|
43
|
-
//# sourceMappingURL=AuthLayout-
|
|
43
|
+
//# sourceMappingURL=AuthLayout-BDRJFSpi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthLayout-
|
|
1
|
+
{"version":3,"file":"AuthLayout-BDRJFSpi.js","sources":["../src/components/AuthLayout/AuthLayout.tsx"],"sourcesContent":["import { forwardRef, type CSSProperties, type HTMLAttributes, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Avatar } from '../Avatar'\nimport { Typography } from '../Typography'\nimport type { IconName } from '../../icons/names'\nimport styles from './AuthLayout.module.css'\n\nexport interface AuthLayoutProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Heading — the page name (e.g. `\"Login\"`, `\"Forgot Password\"`, `\"Verify Code\"`). */\n title?: ReactNode\n /** Muted line under the title (e.g. `\"Enter your email to receive a reset link\"`). */\n subtitle?: ReactNode\n /**\n * Brand slot centered on the canvas, above the card (a logo `<img>` / `<svg>` / any node). The slot\n * is the constraint box (capped width + height) — an `<img>`/`<svg>` inside fills it 100% (aspect\n * kept), so you can pass an unsized logo and it's sized/centered for you.\n */\n logo?: ReactNode\n /** Optional glyph in a solid `color`-filled circle above the title — an `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Bottom slot under the form — e.g. a \"Back to login\" / \"Sign up\" link row. */\n footer?: ReactNode\n /** Theme token that tints the `icon` circle. Defaults to `accent`. */\n color?: ThemeColor\n /** Max width of the centered card in px. Defaults to `400`. */\n maxWidth?: number\n /** The auth form (fields + submit) — usually a `<Form>`. */\n children?: ReactNode\n}\n\n/**\n * A ready-made, centered page frame for **authentication pages** (login, forgot-password,\n * reset-password, OTP, …) — so each page just supplies its `title` + form instead of hand-building the\n * layout. Fills the viewport (`100dvh`) with the app `background` canvas and vertically centers a\n * `logo` (on the canvas, above the card) + an elevated `surface` card, as a group. The card stacks: an\n * optional `icon` (in a solid `color`-filled `Avatar` circle), the `title` + `subtitle` (centered), the\n * `children` (your form), and an optional `footer` (link row). Token-only styling; responsive.\n *\n * @example\n * <AuthLayout title=\"Login\" subtitle=\"Welcome back\" logo={<Logo />}>\n * <Form form={form}>…</Form>\n * </AuthLayout>\n */\nexport const AuthLayout = forwardRef<HTMLDivElement, AuthLayoutProps>(function AuthLayout(\n {\n title,\n subtitle,\n logo,\n icon,\n footer,\n color = 'accent',\n maxWidth = 400,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n return (\n <div ref={ref} className={clsx(styles.authLayout, className)} style={style} {...props}>\n {logo != null && <div className={styles.logo}>{logo}</div>}\n <div className={styles.card} style={{ maxWidth } as CSSProperties}>\n {icon != null && (\n <Avatar className={styles.icon} icon={icon} color={color} size=\"lg\" aria-hidden />\n )}\n {(title != null || subtitle != null) && (\n <div className={styles.header}>\n {title != null && (\n <Typography variant=\"h2\" align=\"center\">\n {title}\n </Typography>\n )}\n {subtitle != null && (\n <Typography color=\"muted\" align=\"center\">\n {subtitle}\n </Typography>\n )}\n </div>\n )}\n {children != null && <div className={styles.body}>{children}</div>}\n {footer != null && <div className={styles.footer}>{footer}</div>}\n </div>\n </div>\n )\n})\n"],"names":["AuthLayout","forwardRef","title","subtitle","logo","icon","footer","color","maxWidth","className","style","children","props","ref","jsxs","clsx","styles","jsx","Avatar","Typography"],"mappings":";;;;;;;;;;;;;GA4CaA,IAAaC,EAA4C,SACpE;AAAA,EACE,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,MAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,SACE,gBAAAC,EAAC,OAAA,EAAI,KAAAD,GAAU,WAAWE,EAAKC,EAAO,YAAYP,CAAS,GAAG,OAAAC,GAAe,GAAGE,GAC7E,UAAA;AAAA,IAAAR,KAAQ,QAAQ,gBAAAa,EAAC,OAAA,EAAI,WAAWD,EAAO,MAAO,UAAAZ,GAAK;AAAA,IACpD,gBAAAU,EAAC,SAAI,WAAWE,EAAO,MAAM,OAAO,EAAE,UAAAR,KACnC,UAAA;AAAA,MAAAH,KAAQ,QACP,gBAAAY,EAACC,GAAA,EAAO,WAAWF,EAAO,MAAM,MAAAX,GAAY,OAAAE,GAAc,MAAK,MAAK,eAAW,GAAA,CAAC;AAAA,OAEhFL,KAAS,QAAQC,KAAY,2BAC5B,OAAA,EAAI,WAAWa,EAAO,QACpB,UAAA;AAAA,QAAAd,KAAS,QACR,gBAAAe,EAACE,GAAA,EAAW,SAAQ,MAAK,OAAM,UAC5B,UAAAjB,EAAA,CACH;AAAA,QAEDC,KAAY,QACX,gBAAAc,EAACE,GAAA,EAAW,OAAM,SAAQ,OAAM,UAC7B,UAAAhB,EAAA,CACH;AAAA,MAAA,GAEJ;AAAA,MAEDQ,KAAY,QAAQ,gBAAAM,EAAC,SAAI,WAAWD,EAAO,MAAO,UAAAL,GAAS;AAAA,MAC3DL,KAAU,QAAQ,gBAAAW,EAAC,SAAI,WAAWD,EAAO,QAAS,UAAAV,EAAA,CAAO;AAAA,IAAA,EAAA,CAC5D;AAAA,EAAA,GACF;AAEJ,CAAC;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const a=require("react/jsx-runtime"),g=require("react"),m=require("clsx"),v=require("./Avatar-
|
|
2
|
-
//# sourceMappingURL=AuthLayout-
|
|
1
|
+
"use strict";const a=require("react/jsx-runtime"),g=require("react"),m=require("clsx"),v=require("./Avatar-BwGJl-ru.cjs"),u=require("./Typography-d97DdbNd.cjs"),x="_authLayout_1vumg_3",j="_logo_1vumg_20",L="_card_1vumg_36",N="_icon_1vumg_50",f="_header_1vumg_55",p="_body_1vumg_62",q="_footer_1vumg_68",o={authLayout:x,logo:j,card:L,icon:N,header:f,body:p,footer:q},A=g.forwardRef(function({title:s,subtitle:e,logo:c,icon:r,footer:n,color:l="accent",maxWidth:d=400,className:i,style:h,children:t,..._},y){return a.jsxs("div",{ref:y,className:m.clsx(o.authLayout,i),style:h,..._,children:[c!=null&&a.jsx("div",{className:o.logo,children:c}),a.jsxs("div",{className:o.card,style:{maxWidth:d},children:[r!=null&&a.jsx(v.Avatar,{className:o.icon,icon:r,color:l,size:"lg","aria-hidden":!0}),(s!=null||e!=null)&&a.jsxs("div",{className:o.header,children:[s!=null&&a.jsx(u.Typography,{variant:"h2",align:"center",children:s}),e!=null&&a.jsx(u.Typography,{color:"muted",align:"center",children:e})]}),t!=null&&a.jsx("div",{className:o.body,children:t}),n!=null&&a.jsx("div",{className:o.footer,children:n})]})]})});exports.AuthLayout=A;
|
|
2
|
+
//# sourceMappingURL=AuthLayout-D7mSMdM4.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthLayout-
|
|
1
|
+
{"version":3,"file":"AuthLayout-D7mSMdM4.cjs","sources":["../src/components/AuthLayout/AuthLayout.tsx"],"sourcesContent":["import { forwardRef, type CSSProperties, type HTMLAttributes, type ReactNode } from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Avatar } from '../Avatar'\nimport { Typography } from '../Typography'\nimport type { IconName } from '../../icons/names'\nimport styles from './AuthLayout.module.css'\n\nexport interface AuthLayoutProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Heading — the page name (e.g. `\"Login\"`, `\"Forgot Password\"`, `\"Verify Code\"`). */\n title?: ReactNode\n /** Muted line under the title (e.g. `\"Enter your email to receive a reset link\"`). */\n subtitle?: ReactNode\n /**\n * Brand slot centered on the canvas, above the card (a logo `<img>` / `<svg>` / any node). The slot\n * is the constraint box (capped width + height) — an `<img>`/`<svg>` inside fills it 100% (aspect\n * kept), so you can pass an unsized logo and it's sized/centered for you.\n */\n logo?: ReactNode\n /** Optional glyph in a solid `color`-filled circle above the title — an `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Bottom slot under the form — e.g. a \"Back to login\" / \"Sign up\" link row. */\n footer?: ReactNode\n /** Theme token that tints the `icon` circle. Defaults to `accent`. */\n color?: ThemeColor\n /** Max width of the centered card in px. Defaults to `400`. */\n maxWidth?: number\n /** The auth form (fields + submit) — usually a `<Form>`. */\n children?: ReactNode\n}\n\n/**\n * A ready-made, centered page frame for **authentication pages** (login, forgot-password,\n * reset-password, OTP, …) — so each page just supplies its `title` + form instead of hand-building the\n * layout. Fills the viewport (`100dvh`) with the app `background` canvas and vertically centers a\n * `logo` (on the canvas, above the card) + an elevated `surface` card, as a group. The card stacks: an\n * optional `icon` (in a solid `color`-filled `Avatar` circle), the `title` + `subtitle` (centered), the\n * `children` (your form), and an optional `footer` (link row). Token-only styling; responsive.\n *\n * @example\n * <AuthLayout title=\"Login\" subtitle=\"Welcome back\" logo={<Logo />}>\n * <Form form={form}>…</Form>\n * </AuthLayout>\n */\nexport const AuthLayout = forwardRef<HTMLDivElement, AuthLayoutProps>(function AuthLayout(\n {\n title,\n subtitle,\n logo,\n icon,\n footer,\n color = 'accent',\n maxWidth = 400,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n return (\n <div ref={ref} className={clsx(styles.authLayout, className)} style={style} {...props}>\n {logo != null && <div className={styles.logo}>{logo}</div>}\n <div className={styles.card} style={{ maxWidth } as CSSProperties}>\n {icon != null && (\n <Avatar className={styles.icon} icon={icon} color={color} size=\"lg\" aria-hidden />\n )}\n {(title != null || subtitle != null) && (\n <div className={styles.header}>\n {title != null && (\n <Typography variant=\"h2\" align=\"center\">\n {title}\n </Typography>\n )}\n {subtitle != null && (\n <Typography color=\"muted\" align=\"center\">\n {subtitle}\n </Typography>\n )}\n </div>\n )}\n {children != null && <div className={styles.body}>{children}</div>}\n {footer != null && <div className={styles.footer}>{footer}</div>}\n </div>\n </div>\n )\n})\n"],"names":["AuthLayout","forwardRef","title","subtitle","logo","icon","footer","color","maxWidth","className","style","children","props","ref","jsxs","clsx","styles","jsx","Avatar","Typography"],"mappings":"8WA4CaA,EAAaC,EAAAA,WAA4C,SACpE,CACE,MAAAC,EACA,SAAAC,EACA,KAAAC,EACA,KAAAC,EACA,OAAAC,EACA,MAAAC,EAAQ,SACR,SAAAC,EAAW,IACX,UAAAC,EACA,MAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,OACEC,EAAAA,KAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAAA,KAAKC,EAAO,WAAYP,CAAS,EAAG,MAAAC,EAAe,GAAGE,EAC7E,SAAA,CAAAR,GAAQ,MAAQa,EAAAA,IAAC,MAAA,CAAI,UAAWD,EAAO,KAAO,SAAAZ,EAAK,EACpDU,OAAC,OAAI,UAAWE,EAAO,KAAM,MAAO,CAAE,SAAAR,GACnC,SAAA,CAAAH,GAAQ,MACPY,EAAAA,IAACC,EAAAA,OAAA,CAAO,UAAWF,EAAO,KAAM,KAAAX,EAAY,MAAAE,EAAc,KAAK,KAAK,cAAW,EAAA,CAAC,GAEhFL,GAAS,MAAQC,GAAY,cAC5B,MAAA,CAAI,UAAWa,EAAO,OACpB,SAAA,CAAAd,GAAS,MACRe,MAACE,EAAAA,WAAA,CAAW,QAAQ,KAAK,MAAM,SAC5B,SAAAjB,CAAA,CACH,EAEDC,GAAY,MACXc,MAACE,EAAAA,WAAA,CAAW,MAAM,QAAQ,MAAM,SAC7B,SAAAhB,CAAA,CACH,CAAA,EAEJ,EAEDQ,GAAY,MAAQM,EAAAA,IAAC,OAAI,UAAWD,EAAO,KAAO,SAAAL,EAAS,EAC3DL,GAAU,MAAQW,EAAAA,IAAC,OAAI,UAAWD,EAAO,OAAS,SAAAV,CAAA,CAAO,CAAA,CAAA,CAC5D,CAAA,EACF,CAEJ,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const n=require("react/jsx-runtime"),r=require("react"),N=require("clsx"),f=require("./Icon-
|
|
2
|
-
//# sourceMappingURL=Avatar-
|
|
1
|
+
"use strict";const n=require("react/jsx-runtime"),r=require("react"),N=require("clsx"),f=require("./Icon-BoQmbW7j.cjs"),R=require("./Skeleton-DK0lAjS9.cjs"),w="_avatar_m3hkg_3",C="_circle_m3hkg_17",L="_square_m3hkg_21",P="_img_m3hkg_25",U="_pending_m3hkg_33",z="_imgPending_m3hkg_36",B="_skeleton_m3hkg_39",M="_fallback_m3hkg_49",O="_sm_m3hkg_55",$="_md_m3hkg_61",F="_lg_m3hkg_67",T="_group_m3hkg_75",W="_item_m3hkg_80",t={avatar:w,circle:C,square:L,img:P,pending:U,imgPending:z,skeleton:B,fallback:M,sm:O,md:$,lg:F,group:T,item:W},D=new Set(f.ICON_NAMES);function G(d){const e=d.trim().split(/\s+/).filter(Boolean);return e.length===0?"":e.length===1?e[0].slice(0,2).toUpperCase():(e[0][0]+e[e.length-1][0]).toUpperCase()}const H=r.forwardRef(function({src:e,alt:q,icon:a,name:m,size:g="md",shape:I="circle",color:k="accent",loading:s=!1,className:S,style:j,children:_,...E},y){const[A,h]=r.useState(!1),[p,u]=r.useState(!1),v=r.useRef(null),b=r.useRef(e);b.current!==e&&(b.current=e,h(!1),u(!1));const o=!s&&!!e&&!A;r.useLayoutEffect(()=>{const i=v.current;i!=null&&i.complete&&i.naturalWidth>0&&u(!0)},[e,o]);const x=s||o&&!p,l=q??m;let c;return a!==void 0?c=typeof a=="string"&&D.has(a)?n.jsx(f.Icon,{name:a,size:g}):a:_!=null&&_!==""?c=_:m?c=G(m):c=n.jsx(f.Icon,{name:"User",size:g}),n.jsxs("div",{ref:y,className:N.clsx(t.avatar,t[g],t[I],x&&t.pending,S),style:{"--tz-btn-rgb":`var(--tz-color-${k}-rgb)`,"--tz-btn-on":`var(--tz-color-${k}-contrast, #fff)`,...j},role:!s&&!o&&l?"img":void 0,"aria-label":!s&&!o&&l?l:void 0,"aria-busy":s||void 0,...E,children:[x&&n.jsx(R.Skeleton,{variant:"rect",width:"100%",height:"100%",className:t.skeleton}),s?null:o?n.jsx("img",{ref:v,src:e,alt:l??"",className:N.clsx(t.img,!p&&t.imgPending),onLoad:()=>u(!0),onError:()=>h(!0)}):n.jsx("span",{className:t.fallback,"aria-hidden":l?!0:void 0,children:c})]})});exports.Avatar=H;exports.styles=t;
|
|
2
|
+
//# sourceMappingURL=Avatar-BwGJl-ru.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar-
|
|
1
|
+
{"version":3,"file":"Avatar-BwGJl-ru.cjs","sources":["../src/components/Avatar/Avatar.tsx"],"sourcesContent":["import {\n forwardRef,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { Skeleton } from '../Skeleton'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport styles from './Avatar.module.css'\n\nexport type AvatarSize = 'sm' | 'md' | 'lg'\nexport type AvatarShape = 'circle' | 'square'\n\nexport interface AvatarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Image URL. When set (and it loads), the avatar shows the photo; on error it falls back. */\n src?: string\n /** Alt text for the image / accessible name for an icon-or-initials avatar (falls back to `name`). */\n alt?: string\n /** An icon to show when there's no image — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Full name — used to derive initials (e.g. \"David Savaneli\" → \"DS\") and as the accessible name. */\n name?: string\n /** Preset size: `sm` 32 · `md` 40 · `lg` 48 px. Defaults to `md`. */\n size?: AvatarSize\n /** `circle` (default) or `square` (rounded rectangle). */\n shape?: AvatarShape\n /** Theme palette token for the icon/initials background. Defaults to `accent`. */\n color?: ThemeColor\n /**\n * Render a skeleton disc (same size / shape) instead of any content — while the user is still being\n * fetched. An image avatar also shows the skeleton on its own until the photo has loaded. Defaults to `false`.\n */\n loading?: boolean\n}\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/** First letters of the first and last word, uppercased — e.g. \"David Savaneli\" → \"DS\". */\nfunction initialsFromName(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return ''\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase()\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()\n}\n\n/**\n * A user avatar that shows — in priority order — an image (`src`), an `icon`, explicit `children`\n * (e.g. initials `\"D.S.\"`), initials derived from `name`, or a default user icon. If the image fails\n * to load it falls back automatically; until it has loaded (and whenever `loading` is set) a `Skeleton`\n * of the same size / shape stands in. The icon/initials background is tinted by `color` via the\n * shared `--tz-btn-rgb` / `--tz-btn-on` pattern. Token-only styling; pairs with `AvatarGroup`.\n */\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(function Avatar(\n {\n src,\n alt,\n icon,\n name,\n size = 'md',\n shape = 'circle',\n color = 'accent',\n loading = false,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const [imgError, setImgError] = useState(false)\n const [imgLoaded, setImgLoaded] = useState(false)\n const imgRef = useRef<HTMLImageElement>(null)\n // reset the error when `src` changes, so a new/valid image isn't stuck on the fallback forever\n // (React-blessed \"adjust state on prop change\" — restarts the render, no fallback flash)\n const lastSrc = useRef(src)\n if (lastSrc.current !== src) {\n lastSrc.current = src\n setImgError(false)\n setImgLoaded(false)\n }\n const showImage = !loading && Boolean(src) && !imgError\n // a cached image can finish before React wires `onLoad` — catch that case on mount / src change\n useLayoutEffect(() => {\n const img = imgRef.current\n if (img?.complete && img.naturalWidth > 0) setImgLoaded(true)\n }, [src, showImage])\n // skeleton while fetching the user (`loading`) or while the photo is still on its way\n const pending = loading || (showImage && !imgLoaded)\n const label = alt ?? name\n\n let fallback: ReactNode\n if (icon !== undefined) {\n fallback =\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n } else if (children != null && children !== '') {\n fallback = children\n } else if (name) {\n fallback = initialsFromName(name)\n } else {\n fallback = <Icon name=\"User\" size={size} />\n }\n\n return (\n <div\n ref={ref}\n className={clsx(\n styles.avatar,\n styles[size],\n styles[shape],\n pending && styles.pending,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n role={!loading && !showImage && label ? 'img' : undefined}\n aria-label={!loading && !showImage && label ? label : undefined}\n aria-busy={loading || undefined}\n {...props}\n >\n {pending && (\n <Skeleton variant=\"rect\" width=\"100%\" height=\"100%\" className={styles.skeleton} />\n )}\n {loading ? null : showImage ? (\n <img\n ref={imgRef}\n src={src}\n alt={label ?? ''}\n className={clsx(styles.img, !imgLoaded && styles.imgPending)}\n onLoad={() => setImgLoaded(true)}\n onError={() => setImgError(true)}\n />\n ) : (\n <span className={styles.fallback} aria-hidden={label ? true : undefined}>\n {fallback}\n </span>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","initialsFromName","name","parts","Avatar","forwardRef","src","alt","icon","size","shape","color","loading","className","style","children","props","ref","imgError","setImgError","useState","imgLoaded","setImgLoaded","imgRef","useRef","lastSrc","showImage","useLayoutEffect","img","pending","label","fallback","jsx","Icon","jsxs","clsx","styles","Skeleton"],"mappings":"ohBAyCMA,EAAgB,IAAI,IAAYC,YAAU,EAGhD,SAASC,EAAiBC,EAAsB,CAC9C,MAAMC,EAAQD,EAAK,KAAA,EAAO,MAAM,KAAK,EAAE,OAAO,OAAO,EACrD,OAAIC,EAAM,SAAW,EAAU,GAC3BA,EAAM,SAAW,EAAUA,EAAM,CAAC,EAAE,MAAM,EAAG,CAAC,EAAE,YAAA,GAC5CA,EAAM,CAAC,EAAE,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,EAAE,CAAC,GAAG,YAAA,CACpD,CASO,MAAMC,EAASC,EAAAA,WAAwC,SAC5D,CACE,IAAAC,EACA,IAAAC,EACA,KAAAC,EACA,KAAAN,EACA,KAAAO,EAAO,KACP,MAAAC,EAAQ,SACR,MAAAC,EAAQ,SACR,QAAAC,EAAU,GACV,UAAAC,EACA,MAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,KAAM,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAAS,EAAK,EACxC,CAACC,EAAWC,CAAY,EAAIF,EAAAA,SAAS,EAAK,EAC1CG,EAASC,EAAAA,OAAyB,IAAI,EAGtCC,EAAUD,EAAAA,OAAOlB,CAAG,EACtBmB,EAAQ,UAAYnB,IACtBmB,EAAQ,QAAUnB,EAClBa,EAAY,EAAK,EACjBG,EAAa,EAAK,GAEpB,MAAMI,EAAY,CAACd,GAAW,EAAQN,GAAQ,CAACY,EAE/CS,EAAAA,gBAAgB,IAAM,CACpB,MAAMC,EAAML,EAAO,QACfK,GAAA,MAAAA,EAAK,UAAYA,EAAI,aAAe,KAAgB,EAAI,CAC9D,EAAG,CAACtB,EAAKoB,CAAS,CAAC,EAEnB,MAAMG,EAAUjB,GAAYc,GAAa,CAACL,EACpCS,EAAQvB,GAAOL,EAErB,IAAI6B,EACJ,OAAIvB,IAAS,OACXuB,EACE,OAAOvB,GAAS,UAAYT,EAAc,IAAIS,CAAI,EAChDwB,EAAAA,IAACC,EAAAA,KAAA,CAAK,KAAMzB,EAAkB,KAAAC,CAAA,CAAY,EAE1CD,EAEKO,GAAY,MAAQA,IAAa,GAC1CgB,EAAWhB,EACFb,EACT6B,EAAW9B,EAAiBC,CAAI,EAEhC6B,EAAWC,EAAAA,IAACC,EAAAA,KAAA,CAAK,KAAK,OAAO,KAAAxB,EAAY,EAIzCyB,EAAAA,KAAC,MAAA,CACC,IAAAjB,EACA,UAAWkB,EAAAA,KACTC,EAAO,OACPA,EAAO3B,CAAI,EACX2B,EAAO1B,CAAK,EACZmB,GAAWO,EAAO,QAClBvB,CAAA,EAEF,MACE,CACE,eAAgB,kBAAkBF,CAAK,QACvC,cAAe,kBAAkBA,CAAK,mBACtC,GAAGG,CAAA,EAGP,KAAM,CAACF,GAAW,CAACc,GAAaI,EAAQ,MAAQ,OAChD,aAAY,CAAClB,GAAW,CAACc,GAAaI,EAAQA,EAAQ,OACtD,YAAWlB,GAAW,OACrB,GAAGI,EAEH,SAAA,CAAAa,GACCG,EAAAA,IAACK,EAAAA,SAAA,CAAS,QAAQ,OAAO,MAAM,OAAO,OAAO,OAAO,UAAWD,EAAO,QAAA,CAAU,EAEjFxB,EAAU,KAAOc,EAChBM,EAAAA,IAAC,MAAA,CACC,IAAKT,EACL,IAAAjB,EACA,IAAKwB,GAAS,GACd,UAAWK,EAAAA,KAAKC,EAAO,IAAK,CAACf,GAAae,EAAO,UAAU,EAC3D,OAAQ,IAAMd,EAAa,EAAI,EAC/B,QAAS,IAAMH,EAAY,EAAI,CAAA,CAAA,EAGjCa,MAAC,OAAA,CAAK,UAAWI,EAAO,SAAU,cAAaN,EAAQ,GAAO,OAC3D,SAAAC,CAAA,CACH,CAAA,CAAA,CAAA,CAIR,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as l, jsxs as P } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as q, useState as b, useRef as N, useLayoutEffect as R } from "react";
|
|
3
3
|
import { clsx as E } from "clsx";
|
|
4
|
-
import { b as S, a as U } from "./Icon-
|
|
4
|
+
import { b as S, a as U } from "./Icon-DMMO32p6.js";
|
|
5
5
|
import { S as j } from "./Skeleton-_-uGax2j.js";
|
|
6
6
|
const z = "_avatar_m3hkg_3", B = "_circle_m3hkg_17", M = "_square_m3hkg_21", O = "_img_m3hkg_25", $ = "_pending_m3hkg_33", F = "_imgPending_m3hkg_36", T = "_skeleton_m3hkg_39", W = "_fallback_m3hkg_49", D = "_sm_m3hkg_55", G = "_md_m3hkg_61", H = "_lg_m3hkg_67", J = "_group_m3hkg_75", K = "_item_m3hkg_80", e = {
|
|
7
7
|
avatar: z,
|
|
@@ -86,4 +86,4 @@ export {
|
|
|
86
86
|
at as A,
|
|
87
87
|
e as s
|
|
88
88
|
};
|
|
89
|
-
//# sourceMappingURL=Avatar-
|
|
89
|
+
//# sourceMappingURL=Avatar-C4qgzth2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar-
|
|
1
|
+
{"version":3,"file":"Avatar-C4qgzth2.js","sources":["../src/components/Avatar/Avatar.tsx"],"sourcesContent":["import {\n forwardRef,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { Skeleton } from '../Skeleton'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport styles from './Avatar.module.css'\n\nexport type AvatarSize = 'sm' | 'md' | 'lg'\nexport type AvatarShape = 'circle' | 'square'\n\nexport interface AvatarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Image URL. When set (and it loads), the avatar shows the photo; on error it falls back. */\n src?: string\n /** Alt text for the image / accessible name for an icon-or-initials avatar (falls back to `name`). */\n alt?: string\n /** An icon to show when there's no image — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Full name — used to derive initials (e.g. \"David Savaneli\" → \"DS\") and as the accessible name. */\n name?: string\n /** Preset size: `sm` 32 · `md` 40 · `lg` 48 px. Defaults to `md`. */\n size?: AvatarSize\n /** `circle` (default) or `square` (rounded rectangle). */\n shape?: AvatarShape\n /** Theme palette token for the icon/initials background. Defaults to `accent`. */\n color?: ThemeColor\n /**\n * Render a skeleton disc (same size / shape) instead of any content — while the user is still being\n * fetched. An image avatar also shows the skeleton on its own until the photo has loaded. Defaults to `false`.\n */\n loading?: boolean\n}\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/** First letters of the first and last word, uppercased — e.g. \"David Savaneli\" → \"DS\". */\nfunction initialsFromName(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return ''\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase()\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()\n}\n\n/**\n * A user avatar that shows — in priority order — an image (`src`), an `icon`, explicit `children`\n * (e.g. initials `\"D.S.\"`), initials derived from `name`, or a default user icon. If the image fails\n * to load it falls back automatically; until it has loaded (and whenever `loading` is set) a `Skeleton`\n * of the same size / shape stands in. The icon/initials background is tinted by `color` via the\n * shared `--tz-btn-rgb` / `--tz-btn-on` pattern. Token-only styling; pairs with `AvatarGroup`.\n */\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(function Avatar(\n {\n src,\n alt,\n icon,\n name,\n size = 'md',\n shape = 'circle',\n color = 'accent',\n loading = false,\n className,\n style,\n children,\n ...props\n },\n ref,\n) {\n const [imgError, setImgError] = useState(false)\n const [imgLoaded, setImgLoaded] = useState(false)\n const imgRef = useRef<HTMLImageElement>(null)\n // reset the error when `src` changes, so a new/valid image isn't stuck on the fallback forever\n // (React-blessed \"adjust state on prop change\" — restarts the render, no fallback flash)\n const lastSrc = useRef(src)\n if (lastSrc.current !== src) {\n lastSrc.current = src\n setImgError(false)\n setImgLoaded(false)\n }\n const showImage = !loading && Boolean(src) && !imgError\n // a cached image can finish before React wires `onLoad` — catch that case on mount / src change\n useLayoutEffect(() => {\n const img = imgRef.current\n if (img?.complete && img.naturalWidth > 0) setImgLoaded(true)\n }, [src, showImage])\n // skeleton while fetching the user (`loading`) or while the photo is still on its way\n const pending = loading || (showImage && !imgLoaded)\n const label = alt ?? name\n\n let fallback: ReactNode\n if (icon !== undefined) {\n fallback =\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n } else if (children != null && children !== '') {\n fallback = children\n } else if (name) {\n fallback = initialsFromName(name)\n } else {\n fallback = <Icon name=\"User\" size={size} />\n }\n\n return (\n <div\n ref={ref}\n className={clsx(\n styles.avatar,\n styles[size],\n styles[shape],\n pending && styles.pending,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n role={!loading && !showImage && label ? 'img' : undefined}\n aria-label={!loading && !showImage && label ? label : undefined}\n aria-busy={loading || undefined}\n {...props}\n >\n {pending && (\n <Skeleton variant=\"rect\" width=\"100%\" height=\"100%\" className={styles.skeleton} />\n )}\n {loading ? null : showImage ? (\n <img\n ref={imgRef}\n src={src}\n alt={label ?? ''}\n className={clsx(styles.img, !imgLoaded && styles.imgPending)}\n onLoad={() => setImgLoaded(true)}\n onError={() => setImgError(true)}\n />\n ) : (\n <span className={styles.fallback} aria-hidden={label ? true : undefined}>\n {fallback}\n </span>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","initialsFromName","name","parts","Avatar","forwardRef","src","alt","icon","size","shape","color","loading","className","style","children","props","ref","imgError","setImgError","useState","imgLoaded","setImgLoaded","imgRef","useRef","lastSrc","showImage","useLayoutEffect","img","pending","label","fallback","jsx","Icon","jsxs","clsx","styles","Skeleton"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const i=require("react/jsx-runtime"),e=require("react"),p=require("clsx"),r=require("./Avatar-
|
|
2
|
-
//# sourceMappingURL=AvatarGroup-
|
|
1
|
+
"use strict";const i=require("react/jsx-runtime"),e=require("react"),p=require("clsx"),r=require("./Avatar-BwGJl-ru.cjs"),g={sm:"-6px",md:"-8px",lg:"-10px"},h=e.forwardRef(function({children:u,max:s,size:l="md",color:m="accent",className:d,style:v,...x},y){const a=e.Children.toArray(u).filter(e.isValidElement),t=a.length,A=s&&s>0&&t>s?s-1:t,c=a.slice(0,A),o=t-c.length;return i.jsxs("div",{ref:y,className:p.clsx(r.styles.group,d),style:{"--avatar-overlap":g[l],...v},...x,children:[c.map((n,f)=>e.cloneElement(n,{size:l,className:p.clsx(r.styles.item,n.props.className),style:{zIndex:t-f,...n.props.style}})),o>0&&i.jsxs(r.Avatar,{size:l,color:m,className:r.styles.item,style:{zIndex:0},children:["+",o]})]})});exports.AvatarGroup=h;
|
|
2
|
+
//# sourceMappingURL=AvatarGroup-B8u8ONs5.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AvatarGroup-
|
|
1
|
+
{"version":3,"file":"AvatarGroup-B8u8ONs5.cjs","sources":["../src/components/Avatar/AvatarGroup.tsx"],"sourcesContent":["import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Avatar, type AvatarProps, type AvatarSize } from './Avatar'\nimport styles from './Avatar.module.css'\n\nexport interface AvatarGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'> {\n /** `Avatar` elements to overlap. */\n children: ReactNode\n /** Show at most this many slots; the rest collapse into a trailing `+N` avatar. */\n max?: number\n /** Size applied to every avatar in the group (incl. the `+N`). Defaults to `md`. */\n size?: AvatarSize\n /** Theme palette token for the `+N` surplus avatar. Defaults to `accent`. */\n color?: ThemeColor\n}\n\nconst OVERLAP: Record<AvatarSize, string> = { sm: '-6px', md: '-8px', lg: '-10px' }\n\n/**\n * Overlaps a row of `Avatar`s with a ring between them, and collapses the overflow past `max` into a\n * trailing `+N` avatar (like a stacked team list). All avatars are normalized to the group's `size`.\n * Token-only styling.\n */\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(function AvatarGroup(\n { children, max, size = 'md', color = 'accent', className, style, ...props },\n ref,\n) {\n const items = Children.toArray(children).filter(isValidElement) as ReactElement<AvatarProps>[]\n const total = items.length\n const limit = max && max > 0 && total > max ? max - 1 : total\n const shown = items.slice(0, limit)\n const surplus = total - shown.length\n\n return (\n <div\n ref={ref}\n className={clsx(styles.group, className)}\n style={{ '--avatar-overlap': OVERLAP[size], ...style } as CSSProperties}\n {...props}\n >\n {shown.map((child, index) =>\n cloneElement(child, {\n size,\n className: clsx(styles.item, child.props.className),\n style: { zIndex: total - index, ...child.props.style } as CSSProperties,\n }),\n )}\n {surplus > 0 && (\n <Avatar size={size} color={color} className={styles.item} style={{ zIndex: 0 }}>\n +{surplus}\n </Avatar>\n )}\n </div>\n )\n})\n"],"names":["OVERLAP","AvatarGroup","forwardRef","children","max","size","color","className","style","props","ref","items","Children","isValidElement","total","limit","shown","surplus","jsxs","clsx","styles","child","index","cloneElement","Avatar"],"mappings":"0HA0BMA,EAAsC,CAAE,GAAI,OAAQ,GAAI,OAAQ,GAAI,OAAA,EAO7DC,EAAcC,EAAAA,WAA6C,SACtE,CAAE,SAAAC,EAAU,IAAAC,EAAK,KAAAC,EAAO,KAAM,MAAAC,EAAQ,SAAU,UAAAC,EAAW,MAAAC,EAAO,GAAGC,CAAA,EACrEC,EACA,CACA,MAAMC,EAAQC,EAAAA,SAAS,QAAQT,CAAQ,EAAE,OAAOU,gBAAc,EACxDC,EAAQH,EAAM,OACdI,EAAQX,GAAOA,EAAM,GAAKU,EAAQV,EAAMA,EAAM,EAAIU,EAClDE,EAAQL,EAAM,MAAM,EAAGI,CAAK,EAC5BE,EAAUH,EAAQE,EAAM,OAE9B,OACEE,EAAAA,KAAC,MAAA,CACC,IAAAR,EACA,UAAWS,EAAAA,KAAKC,SAAO,MAAOb,CAAS,EACvC,MAAO,CAAE,mBAAoBP,EAAQK,CAAI,EAAG,GAAGG,CAAA,EAC9C,GAAGC,EAEH,SAAA,CAAAO,EAAM,IAAI,CAACK,EAAOC,IACjBC,EAAAA,aAAaF,EAAO,CAClB,KAAAhB,EACA,UAAWc,EAAAA,KAAKC,EAAAA,OAAO,KAAMC,EAAM,MAAM,SAAS,EAClD,MAAO,CAAE,OAAQP,EAAQQ,EAAO,GAAGD,EAAM,MAAM,KAAA,CAAM,CACtD,CAAA,EAEFJ,EAAU,GACTC,EAAAA,KAACM,EAAAA,OAAA,CAAO,KAAAnB,EAAY,MAAAC,EAAc,UAAWc,EAAAA,OAAO,KAAM,MAAO,CAAE,OAAQ,GAAK,SAAA,CAAA,IAC5EH,CAAA,CAAA,CACJ,CAAA,CAAA,CAAA,CAIR,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as m } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as x, Children as g, isValidElement as h, cloneElement as N } from "react";
|
|
3
3
|
import { clsx as p } from "clsx";
|
|
4
|
-
import { s as o, A as E } from "./Avatar-
|
|
4
|
+
import { s as o, A as E } from "./Avatar-C4qgzth2.js";
|
|
5
5
|
const w = { sm: "-6px", md: "-8px", lg: "-10px" }, C = x(function({ children: c, max: t, size: r = "md", color: i = "accent", className: d, style: f, ...u }, A) {
|
|
6
6
|
const a = g.toArray(c).filter(h), s = a.length, v = t && t > 0 && s > t ? t - 1 : s, l = a.slice(0, v), n = s - l.length;
|
|
7
7
|
return /* @__PURE__ */ m(
|
|
@@ -30,4 +30,4 @@ const w = { sm: "-6px", md: "-8px", lg: "-10px" }, C = x(function({ children: c,
|
|
|
30
30
|
export {
|
|
31
31
|
C as A
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=AvatarGroup-
|
|
33
|
+
//# sourceMappingURL=AvatarGroup-BqxTFzRc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AvatarGroup-
|
|
1
|
+
{"version":3,"file":"AvatarGroup-BqxTFzRc.js","sources":["../src/components/Avatar/AvatarGroup.tsx"],"sourcesContent":["import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Avatar, type AvatarProps, type AvatarSize } from './Avatar'\nimport styles from './Avatar.module.css'\n\nexport interface AvatarGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'> {\n /** `Avatar` elements to overlap. */\n children: ReactNode\n /** Show at most this many slots; the rest collapse into a trailing `+N` avatar. */\n max?: number\n /** Size applied to every avatar in the group (incl. the `+N`). Defaults to `md`. */\n size?: AvatarSize\n /** Theme palette token for the `+N` surplus avatar. Defaults to `accent`. */\n color?: ThemeColor\n}\n\nconst OVERLAP: Record<AvatarSize, string> = { sm: '-6px', md: '-8px', lg: '-10px' }\n\n/**\n * Overlaps a row of `Avatar`s with a ring between them, and collapses the overflow past `max` into a\n * trailing `+N` avatar (like a stacked team list). All avatars are normalized to the group's `size`.\n * Token-only styling.\n */\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(function AvatarGroup(\n { children, max, size = 'md', color = 'accent', className, style, ...props },\n ref,\n) {\n const items = Children.toArray(children).filter(isValidElement) as ReactElement<AvatarProps>[]\n const total = items.length\n const limit = max && max > 0 && total > max ? max - 1 : total\n const shown = items.slice(0, limit)\n const surplus = total - shown.length\n\n return (\n <div\n ref={ref}\n className={clsx(styles.group, className)}\n style={{ '--avatar-overlap': OVERLAP[size], ...style } as CSSProperties}\n {...props}\n >\n {shown.map((child, index) =>\n cloneElement(child, {\n size,\n className: clsx(styles.item, child.props.className),\n style: { zIndex: total - index, ...child.props.style } as CSSProperties,\n }),\n )}\n {surplus > 0 && (\n <Avatar size={size} color={color} className={styles.item} style={{ zIndex: 0 }}>\n +{surplus}\n </Avatar>\n )}\n </div>\n )\n})\n"],"names":["OVERLAP","AvatarGroup","forwardRef","children","max","size","color","className","style","props","ref","items","Children","isValidElement","total","limit","shown","surplus","jsxs","clsx","styles","child","index","cloneElement","Avatar"],"mappings":";;;;AA0BA,MAAMA,IAAsC,EAAE,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAA,GAO7DC,IAAcC,EAA6C,SACtE,EAAE,UAAAC,GAAU,KAAAC,GAAK,MAAAC,IAAO,MAAM,OAAAC,IAAQ,UAAU,WAAAC,GAAW,OAAAC,GAAO,GAAGC,EAAA,GACrEC,GACA;AACA,QAAMC,IAAQC,EAAS,QAAQT,CAAQ,EAAE,OAAOU,CAAc,GACxDC,IAAQH,EAAM,QACdI,IAAQX,KAAOA,IAAM,KAAKU,IAAQV,IAAMA,IAAM,IAAIU,GAClDE,IAAQL,EAAM,MAAM,GAAGI,CAAK,GAC5BE,IAAUH,IAAQE,EAAM;AAE9B,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAR;AAAA,MACA,WAAWS,EAAKC,EAAO,OAAOb,CAAS;AAAA,MACvC,OAAO,EAAE,oBAAoBP,EAAQK,CAAI,GAAG,GAAGG,EAAA;AAAA,MAC9C,GAAGC;AAAA,MAEH,UAAA;AAAA,QAAAO,EAAM;AAAA,UAAI,CAACK,GAAOC,MACjBC,EAAaF,GAAO;AAAA,YAClB,MAAAhB;AAAA,YACA,WAAWc,EAAKC,EAAO,MAAMC,EAAM,MAAM,SAAS;AAAA,YAClD,OAAO,EAAE,QAAQP,IAAQQ,GAAO,GAAGD,EAAM,MAAM,MAAA;AAAA,UAAM,CACtD;AAAA,QAAA;AAAA,QAEFJ,IAAU,KACT,gBAAAC,EAACM,GAAA,EAAO,MAAAnB,GAAY,OAAAC,GAAc,WAAWc,EAAO,MAAM,OAAO,EAAE,QAAQ,KAAK,UAAA;AAAA,UAAA;AAAA,UAC5EH;AAAA,QAAA,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR,CAAC;"}
|