@techzyapp/ui-library 1.0.20 → 1.0.21
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-Dy_dM79Y.cjs → Accordion-P3PNqSER.cjs} +2 -2
- package/dist/{Accordion-Dy_dM79Y.cjs.map → Accordion-P3PNqSER.cjs.map} +1 -1
- package/dist/{Accordion-CAxa1I-m.js → Accordion-w-w_WxxV.js} +3 -3
- package/dist/{Accordion-CAxa1I-m.js.map → Accordion-w-w_WxxV.js.map} +1 -1
- package/dist/{AdminRoot-DlpMJNTx.cjs → AdminRoot-BDRLuMX6.cjs} +2 -2
- package/dist/{AdminRoot-DlpMJNTx.cjs.map → AdminRoot-BDRLuMX6.cjs.map} +1 -1
- package/dist/{AdminRoot-B2J1cHK5.js → AdminRoot-DvF0js0q.js} +4 -4
- package/dist/{AdminRoot-B2J1cHK5.js.map → AdminRoot-DvF0js0q.js.map} +1 -1
- package/dist/{Alert-DRZdNwDm.cjs → Alert-CwoRkKq4.cjs} +2 -2
- package/dist/{Alert-DRZdNwDm.cjs.map → Alert-CwoRkKq4.cjs.map} +1 -1
- package/dist/{Alert-yldGvhVM.js → Alert-DPYmdaWs.js} +5 -5
- package/dist/{Alert-yldGvhVM.js.map → Alert-DPYmdaWs.js.map} +1 -1
- package/dist/{AuthLayout-B1tzhzHo.cjs → AuthLayout-BRUxDgzs.cjs} +2 -2
- package/dist/{AuthLayout-B1tzhzHo.cjs.map → AuthLayout-BRUxDgzs.cjs.map} +1 -1
- package/dist/{AuthLayout-j7EAPPXT.js → AuthLayout-CP9qu6Bv.js} +2 -2
- package/dist/{AuthLayout-j7EAPPXT.js.map → AuthLayout-CP9qu6Bv.js.map} +1 -1
- package/dist/{Avatar-_ufXh3AY.cjs → Avatar-Dgf04PBC.cjs} +2 -2
- package/dist/{Avatar-_ufXh3AY.cjs.map → Avatar-Dgf04PBC.cjs.map} +1 -1
- package/dist/{Avatar-BJVCdo-K.js → Avatar-Q50J8wdN.js} +3 -3
- package/dist/{Avatar-BJVCdo-K.js.map → Avatar-Q50J8wdN.js.map} +1 -1
- package/dist/{AvatarGroup-DdJf4aT7.js → AvatarGroup-YaNasLMS.js} +2 -2
- package/dist/{AvatarGroup-DdJf4aT7.js.map → AvatarGroup-YaNasLMS.js.map} +1 -1
- package/dist/{AvatarGroup-TW1pt4tj.cjs → AvatarGroup-uW0SD5P4.cjs} +2 -2
- package/dist/{AvatarGroup-TW1pt4tj.cjs.map → AvatarGroup-uW0SD5P4.cjs.map} +1 -1
- package/dist/{Breadcrumbs-f0GE4lCI.cjs → Breadcrumbs-CknDBLMw.cjs} +2 -2
- package/dist/{Breadcrumbs-f0GE4lCI.cjs.map → Breadcrumbs-CknDBLMw.cjs.map} +1 -1
- package/dist/{Breadcrumbs-FpIOHx_q.js → Breadcrumbs-l0PlUpQ4.js} +5 -5
- package/dist/{Breadcrumbs-FpIOHx_q.js.map → Breadcrumbs-l0PlUpQ4.js.map} +1 -1
- package/dist/{Button-Cu0XdnW6.cjs → Button-BdihbLYJ.cjs} +2 -2
- package/dist/{Button-Cu0XdnW6.cjs.map → Button-BdihbLYJ.cjs.map} +1 -1
- package/dist/{Button-BkjZ7wEu.js → Button-RljTGqHl.js} +2 -2
- package/dist/{Button-BkjZ7wEu.js.map → Button-RljTGqHl.js.map} +1 -1
- package/dist/{Calendar-DsJ6GICt.js → Calendar-CKCikOQL.js} +4 -4
- package/dist/{Calendar-DsJ6GICt.js.map → Calendar-CKCikOQL.js.map} +1 -1
- package/dist/{Calendar-CGQCditF.cjs → Calendar-DVg1uQuj.cjs} +2 -2
- package/dist/{Calendar-CGQCditF.cjs.map → Calendar-DVg1uQuj.cjs.map} +1 -1
- package/dist/{Card-CumMi_XB.js → Card-B0bYi4g2.js} +4 -4
- package/dist/{Card-CumMi_XB.js.map → Card-B0bYi4g2.js.map} +1 -1
- package/dist/{Card-DGTGdaTZ.cjs → Card-BYFuYD-a.cjs} +2 -2
- package/dist/{Card-DGTGdaTZ.cjs.map → Card-BYFuYD-a.cjs.map} +1 -1
- package/dist/Checkbox-ZYOSBYRt.js +98 -0
- package/dist/Checkbox-ZYOSBYRt.js.map +1 -0
- package/dist/Checkbox-fzJCwe0j.cjs +2 -0
- package/dist/Checkbox-fzJCwe0j.cjs.map +1 -0
- package/dist/{Chip-D83svOCW.js → Chip-BiqfnRUi.js} +3 -3
- package/dist/{Chip-D83svOCW.js.map → Chip-BiqfnRUi.js.map} +1 -1
- package/dist/{Chip-CJuAvgst.cjs → Chip-CdKUtUGE.cjs} +2 -2
- package/dist/{Chip-CJuAvgst.cjs.map → Chip-CdKUtUGE.cjs.map} +1 -1
- package/dist/{ChoiceCardGroup-CvFzZlgI.js → ChoiceCardGroup-DBohUnRj.js} +3 -3
- package/dist/{ChoiceCardGroup-CvFzZlgI.js.map → ChoiceCardGroup-DBohUnRj.js.map} +1 -1
- package/dist/{ChoiceCardGroup-6eFM1eL0.cjs → ChoiceCardGroup-d0VVTUi5.cjs} +2 -2
- package/dist/{ChoiceCardGroup-6eFM1eL0.cjs.map → ChoiceCardGroup-d0VVTUi5.cjs.map} +1 -1
- package/dist/{CodeBlock-BK_KXhos.js → CodeBlock-BX_0tpk3.js} +4 -4
- package/dist/{CodeBlock-BK_KXhos.js.map → CodeBlock-BX_0tpk3.js.map} +1 -1
- package/dist/{CodeBlock-C_UDrrY6.cjs → CodeBlock-CAAggVXS.cjs} +2 -2
- package/dist/{CodeBlock-C_UDrrY6.cjs.map → CodeBlock-CAAggVXS.cjs.map} +1 -1
- package/dist/{ColorPicker-BmxZnsNC.cjs → ColorPicker-BCSaT1A-.cjs} +2 -2
- package/dist/{ColorPicker-BmxZnsNC.cjs.map → ColorPicker-BCSaT1A-.cjs.map} +1 -1
- package/dist/{ColorPicker-DLnB_AvZ.js → ColorPicker-DhSlvwNj.js} +3 -3
- package/dist/{ColorPicker-DLnB_AvZ.js.map → ColorPicker-DhSlvwNj.js.map} +1 -1
- package/dist/{ColorPickerPanel-CoyKplF5.cjs → ColorPickerPanel-BOGYXXF1.cjs} +2 -2
- package/dist/{ColorPickerPanel-CoyKplF5.cjs.map → ColorPickerPanel-BOGYXXF1.cjs.map} +1 -1
- package/dist/{ColorPickerPanel-CG9idF4A.js → ColorPickerPanel-D4t3b9bB.js} +3 -3
- package/dist/{ColorPickerPanel-CG9idF4A.js.map → ColorPickerPanel-D4t3b9bB.js.map} +1 -1
- package/dist/{ConfigProvider-h1WoGC3R.cjs → ConfigProvider-C7DUWHrb.cjs} +2 -2
- package/dist/{ConfigProvider-h1WoGC3R.cjs.map → ConfigProvider-C7DUWHrb.cjs.map} +1 -1
- package/dist/{ConfigProvider-DDuIJSM7.js → ConfigProvider-DT0yrgmd.js} +2 -2
- package/dist/{ConfigProvider-DDuIJSM7.js.map → ConfigProvider-DT0yrgmd.js.map} +1 -1
- package/dist/{CopyButton-tRMAy59I.cjs → CopyButton-3585thVM.cjs} +2 -2
- package/dist/{CopyButton-tRMAy59I.cjs.map → CopyButton-3585thVM.cjs.map} +1 -1
- package/dist/{CopyButton-DdQ-8ExN.js → CopyButton-BEY1gJzK.js} +4 -4
- package/dist/{CopyButton-DdQ-8ExN.js.map → CopyButton-BEY1gJzK.js.map} +1 -1
- package/dist/{DashedButton-q7AOqKUE.cjs → DashedButton-3C4IZuo4.cjs} +2 -2
- package/dist/{DashedButton-q7AOqKUE.cjs.map → DashedButton-3C4IZuo4.cjs.map} +1 -1
- package/dist/{DashedButton-DeiALUPA.js → DashedButton-BXZAyMtw.js} +3 -3
- package/dist/{DashedButton-DeiALUPA.js.map → DashedButton-BXZAyMtw.js.map} +1 -1
- package/dist/{DatePicker-pz634ktl.js → DatePicker-CEFGgXLF.js} +5 -5
- package/dist/{DatePicker-pz634ktl.js.map → DatePicker-CEFGgXLF.js.map} +1 -1
- package/dist/{DatePicker-eryY6Xmx.cjs → DatePicker-Dyj2halw.cjs} +2 -2
- package/dist/{DatePicker-eryY6Xmx.cjs.map → DatePicker-Dyj2halw.cjs.map} +1 -1
- package/dist/{DateTimePicker-CmH3ZuzN.cjs → DateTimePicker-CjX4-8PP.cjs} +2 -2
- package/dist/{DateTimePicker-CmH3ZuzN.cjs.map → DateTimePicker-CjX4-8PP.cjs.map} +1 -1
- package/dist/{DateTimePicker-BJLq9Fud.js → DateTimePicker-hmYBEuUM.js} +8 -8
- package/dist/{DateTimePicker-BJLq9Fud.js.map → DateTimePicker-hmYBEuUM.js.map} +1 -1
- package/dist/{EmptyState-Cxf4H8Cc.cjs → EmptyState-Bj-vX_UV.cjs} +2 -2
- package/dist/{EmptyState-Cxf4H8Cc.cjs.map → EmptyState-Bj-vX_UV.cjs.map} +1 -1
- package/dist/{EmptyState-B2QPNhWW.js → EmptyState-DJDNLKT7.js} +4 -4
- package/dist/{EmptyState-B2QPNhWW.js.map → EmptyState-DJDNLKT7.js.map} +1 -1
- package/dist/{FileCard-Do9D72NA.js → FileCard-C9Ncifnu.js} +5 -5
- package/dist/{FileCard-Do9D72NA.js.map → FileCard-C9Ncifnu.js.map} +1 -1
- package/dist/{FileCard-D0Sa7WJt.cjs → FileCard-Dr5-z1R3.cjs} +2 -2
- package/dist/{FileCard-D0Sa7WJt.cjs.map → FileCard-Dr5-z1R3.cjs.map} +1 -1
- package/dist/{FileUploader-B1Arfj1a.cjs → FileUploader-DeyZENqq.cjs} +2 -2
- package/dist/{FileUploader-B1Arfj1a.cjs.map → FileUploader-DeyZENqq.cjs.map} +1 -1
- package/dist/{FileUploader-4900qKEE.js → FileUploader-XFmBNkA0.js} +6 -6
- package/dist/{FileUploader-4900qKEE.js.map → FileUploader-XFmBNkA0.js.map} +1 -1
- package/dist/{Flag-DNhhLtCC.js → Flag-Bs0xNP-P.js} +2 -2
- package/dist/{Flag-DNhhLtCC.js.map → Flag-Bs0xNP-P.js.map} +1 -1
- package/dist/{Flag-D7Vlczlw.cjs → Flag-Bxnx26DM.cjs} +2 -2
- package/dist/{Flag-D7Vlczlw.cjs.map → Flag-Bxnx26DM.cjs.map} +1 -1
- package/dist/{FullscreenToggle-dU2ai_OZ.cjs → FullscreenToggle-BncatGKj.cjs} +2 -2
- package/dist/{FullscreenToggle-dU2ai_OZ.cjs.map → FullscreenToggle-BncatGKj.cjs.map} +1 -1
- package/dist/{FullscreenToggle-Bc4fB-Mi.js → FullscreenToggle-DMlp05UN.js} +4 -4
- package/dist/{FullscreenToggle-Bc4fB-Mi.js.map → FullscreenToggle-DMlp05UN.js.map} +1 -1
- package/dist/Icon-BVULqOJD.cjs +2 -0
- package/dist/Icon-BVULqOJD.cjs.map +1 -0
- package/dist/{Icon-CophpkHo.js → Icon-DaTvzLBu.js} +2 -1
- package/dist/Icon-DaTvzLBu.js.map +1 -0
- package/dist/{IconButton-DpTxmj3d.js → IconButton-DXMmtuLA.js} +2 -2
- package/dist/{IconButton-DpTxmj3d.js.map → IconButton-DXMmtuLA.js.map} +1 -1
- package/dist/{IconButton-DyRC514t.cjs → IconButton-Lv0sDDR9.cjs} +2 -2
- package/dist/{IconButton-DyRC514t.cjs.map → IconButton-Lv0sDDR9.cjs.map} +1 -1
- package/dist/{ListItem-B4Upc0Hy.js → ListItem-Cn15lJBr.js} +3 -3
- package/dist/{ListItem-B4Upc0Hy.js.map → ListItem-Cn15lJBr.js.map} +1 -1
- package/dist/{ListItem-DWQorRxG.cjs → ListItem-yXXjtepZ.cjs} +2 -2
- package/dist/{ListItem-DWQorRxG.cjs.map → ListItem-yXXjtepZ.cjs.map} +1 -1
- package/dist/{Loader-B45H2SMP.cjs → Loader-53HFNMVX.cjs} +2 -2
- package/dist/{Loader-B45H2SMP.cjs.map → Loader-53HFNMVX.cjs.map} +1 -1
- package/dist/{Loader-B9VXX401.js → Loader-WsjQFl4p.js} +2 -2
- package/dist/{Loader-B9VXX401.js.map → Loader-WsjQFl4p.js.map} +1 -1
- package/dist/{Modal-Us_E-lb2.js → Modal-DBYcoCbJ.js} +5 -5
- package/dist/{Modal-Us_E-lb2.js.map → Modal-DBYcoCbJ.js.map} +1 -1
- package/dist/{Modal-DsoSz0Sp.cjs → Modal-V6eyGSzW.cjs} +2 -2
- package/dist/{Modal-DsoSz0Sp.cjs.map → Modal-V6eyGSzW.cjs.map} +1 -1
- package/dist/{MultiSelect-sKk2KzOd.js → MultiSelect-BsYPr3LD.js} +6 -6
- package/dist/{MultiSelect-sKk2KzOd.js.map → MultiSelect-BsYPr3LD.js.map} +1 -1
- package/dist/{MultiSelect-CtLpWaBX.cjs → MultiSelect-DS2DRpaP.cjs} +2 -2
- package/dist/{MultiSelect-CtLpWaBX.cjs.map → MultiSelect-DS2DRpaP.cjs.map} +1 -1
- package/dist/{NumberField-C6qj3nCa.cjs → NumberField-DC3TdGTt.cjs} +2 -2
- package/dist/{NumberField-C6qj3nCa.cjs.map → NumberField-DC3TdGTt.cjs.map} +1 -1
- package/dist/{NumberField-Cz03nksO.js → NumberField-mFb9pKCx.js} +4 -4
- package/dist/{NumberField-Cz03nksO.js.map → NumberField-mFb9pKCx.js.map} +1 -1
- package/dist/{OtpField-DLXQYMw1.js → OtpField-1ullIIZQ.js} +2 -2
- package/dist/{OtpField-DLXQYMw1.js.map → OtpField-1ullIIZQ.js.map} +1 -1
- package/dist/{OtpField-B46P6aMy.cjs → OtpField-BYj9SDHb.cjs} +2 -2
- package/dist/{OtpField-B46P6aMy.cjs.map → OtpField-BYj9SDHb.cjs.map} +1 -1
- package/dist/{PageLayout-BfeRjBek.cjs → PageLayout-pYL43wI9.cjs} +2 -2
- package/dist/{PageLayout-BfeRjBek.cjs.map → PageLayout-pYL43wI9.cjs.map} +1 -1
- package/dist/{PageLayout-BWU-p_N9.js → PageLayout-qf0H_EmS.js} +2 -2
- package/dist/{PageLayout-BWU-p_N9.js.map → PageLayout-qf0H_EmS.js.map} +1 -1
- package/dist/{PageNotFound-nvZm-UCG.cjs → PageNotFound-D1795gJ7.cjs} +2 -2
- package/dist/{PageNotFound-nvZm-UCG.cjs.map → PageNotFound-D1795gJ7.cjs.map} +1 -1
- package/dist/{PageNotFound-B_nTMrCD.js → PageNotFound-YGVMVvyG.js} +5 -5
- package/dist/{PageNotFound-B_nTMrCD.js.map → PageNotFound-YGVMVvyG.js.map} +1 -1
- package/dist/{Pagination-BYXUhmSz.js → Pagination-BTvUJiee.js} +3 -3
- package/dist/{Pagination-BYXUhmSz.js.map → Pagination-BTvUJiee.js.map} +1 -1
- package/dist/{Pagination-CsClNqIu.cjs → Pagination-WJq_7QNi.cjs} +2 -2
- package/dist/{Pagination-CsClNqIu.cjs.map → Pagination-WJq_7QNi.cjs.map} +1 -1
- package/dist/{RemoveDialog-PHdZi9-d.js → RemoveDialog-BSQ6EMW-.js} +5 -5
- package/dist/{RemoveDialog-PHdZi9-d.js.map → RemoveDialog-BSQ6EMW-.js.map} +1 -1
- package/dist/{RemoveDialog-D5J9TYap.cjs → RemoveDialog-BhcwsY0q.cjs} +2 -2
- package/dist/{RemoveDialog-D5J9TYap.cjs.map → RemoveDialog-BhcwsY0q.cjs.map} +1 -1
- package/dist/{RichTextEditor-jWv0t3vJ.cjs → RichTextEditor-Bc1fhvzn.cjs} +2 -2
- package/dist/{RichTextEditor-jWv0t3vJ.cjs.map → RichTextEditor-Bc1fhvzn.cjs.map} +1 -1
- package/dist/{RichTextEditor-BcmsnYGJ.js → RichTextEditor-CaGPtwXe.js} +9 -9
- package/dist/{RichTextEditor-BcmsnYGJ.js.map → RichTextEditor-CaGPtwXe.js.map} +1 -1
- package/dist/{RootLayout-q_oWf5et.js → RootLayout-BNwHsuhC.js} +31 -31
- package/dist/{RootLayout-q_oWf5et.js.map → RootLayout-BNwHsuhC.js.map} +1 -1
- package/dist/{RootLayout-DtZcqk9N.cjs → RootLayout-CB-3FgOp.cjs} +2 -2
- package/dist/{RootLayout-DtZcqk9N.cjs.map → RootLayout-CB-3FgOp.cjs.map} +1 -1
- package/dist/{Select-CWCeBQ8Q.cjs → Select-Cx1Yl8nq.cjs} +2 -2
- package/dist/{Select-CWCeBQ8Q.cjs.map → Select-Cx1Yl8nq.cjs.map} +1 -1
- package/dist/{Select-UygxT1Ry.js → Select-vKZzS9K4.js} +6 -6
- package/dist/{Select-UygxT1Ry.js.map → Select-vKZzS9K4.js.map} +1 -1
- package/dist/{Sidebar-C0OJK29L.js → Sidebar-CJ7DtOqb.js} +5 -5
- package/dist/{Sidebar-C0OJK29L.js.map → Sidebar-CJ7DtOqb.js.map} +1 -1
- package/dist/{Sidebar-BfBggyuh.cjs → Sidebar-Cv95DJxZ.cjs} +2 -2
- package/dist/{Sidebar-BfBggyuh.cjs.map → Sidebar-Cv95DJxZ.cjs.map} +1 -1
- package/dist/{SpeedDial-DbvOJ4no.js → SpeedDial-Bb0ioXaO.js} +4 -4
- package/dist/{SpeedDial-DbvOJ4no.js.map → SpeedDial-Bb0ioXaO.js.map} +1 -1
- package/dist/{SpeedDial-cKvuSMuk.cjs → SpeedDial-D6sO-9ES.cjs} +2 -2
- package/dist/{SpeedDial-cKvuSMuk.cjs.map → SpeedDial-D6sO-9ES.cjs.map} +1 -1
- package/dist/{Stepper-BxGrP6JZ.js → Stepper-BaEOUnYe.js} +4 -4
- package/dist/{Stepper-BxGrP6JZ.js.map → Stepper-BaEOUnYe.js.map} +1 -1
- package/dist/{Stepper-Db_ALAc4.cjs → Stepper-CVY8NJEI.cjs} +2 -2
- package/dist/{Stepper-Db_ALAc4.cjs.map → Stepper-CVY8NJEI.cjs.map} +1 -1
- package/dist/{SwatchPicker-DbAU9-ux.cjs → SwatchPicker-CCJltwHI.cjs} +2 -2
- package/dist/{SwatchPicker-DbAU9-ux.cjs.map → SwatchPicker-CCJltwHI.cjs.map} +1 -1
- package/dist/{SwatchPicker-D30aSrbY.js → SwatchPicker-CqyWngFJ.js} +2 -2
- package/dist/{SwatchPicker-D30aSrbY.js.map → SwatchPicker-CqyWngFJ.js.map} +1 -1
- package/dist/{Table--pDmXYad.cjs → Table-AQ7yJhtW.cjs} +2 -2
- package/dist/{Table--pDmXYad.cjs.map → Table-AQ7yJhtW.cjs.map} +1 -1
- package/dist/{Table-CNjnvZ-k.js → Table-wn-B7iLj.js} +17 -17
- package/dist/{Table-CNjnvZ-k.js.map → Table-wn-B7iLj.js.map} +1 -1
- package/dist/{Tabs-ozklGWmX.cjs → Tabs-BtcJ2jBl.cjs} +2 -2
- package/dist/{Tabs-ozklGWmX.cjs.map → Tabs-BtcJ2jBl.cjs.map} +1 -1
- package/dist/{Tabs-B0mWCNaC.js → Tabs-DJMfAUni.js} +4 -4
- package/dist/{Tabs-B0mWCNaC.js.map → Tabs-DJMfAUni.js.map} +1 -1
- package/dist/{TagsField-BIxwLfSJ.cjs → TagsField-4x3RmGwt.cjs} +2 -2
- package/dist/{TagsField-BIxwLfSJ.cjs.map → TagsField-4x3RmGwt.cjs.map} +1 -1
- package/dist/{TagsField-CGFm17lP.js → TagsField-Bvh6Fm5Y.js} +5 -5
- package/dist/{TagsField-CGFm17lP.js.map → TagsField-Bvh6Fm5Y.js.map} +1 -1
- package/dist/{TextField-DvKEj36A.cjs → TextField-DNqnpAWB.cjs} +2 -2
- package/dist/{TextField-DvKEj36A.cjs.map → TextField-DNqnpAWB.cjs.map} +1 -1
- package/dist/{TextField-CRCYLPpr.js → TextField-DcdwUA9d.js} +4 -4
- package/dist/{TextField-CRCYLPpr.js.map → TextField-DcdwUA9d.js.map} +1 -1
- package/dist/{ThemeToggle-BwW9L115.js → ThemeToggle-BVQmSMsj.js} +4 -4
- package/dist/{ThemeToggle-BwW9L115.js.map → ThemeToggle-BVQmSMsj.js.map} +1 -1
- package/dist/{ThemeToggle-DxxLN79b.cjs → ThemeToggle-isboxfZk.cjs} +2 -2
- package/dist/{ThemeToggle-DxxLN79b.cjs.map → ThemeToggle-isboxfZk.cjs.map} +1 -1
- package/dist/{TimeColumns-D3nqkQbh.js → TimeColumns-CFy_PynH.js} +2 -2
- package/dist/{TimeColumns-D3nqkQbh.js.map → TimeColumns-CFy_PynH.js.map} +1 -1
- package/dist/{TimeColumns-DB-V4KpQ.cjs → TimeColumns-DxFjjtc7.cjs} +2 -2
- package/dist/{TimeColumns-DB-V4KpQ.cjs.map → TimeColumns-DxFjjtc7.cjs.map} +1 -1
- package/dist/{TimePicker-D51QkQYy.js → TimePicker-ZO7jOJVa.js} +6 -6
- package/dist/{TimePicker-D51QkQYy.js.map → TimePicker-ZO7jOJVa.js.map} +1 -1
- package/dist/{TimePicker-D__72q2J.cjs → TimePicker-v1yA7Igl.cjs} +2 -2
- package/dist/{TimePicker-D__72q2J.cjs.map → TimePicker-v1yA7Igl.cjs.map} +1 -1
- package/dist/{Timeline-WkV4k_we.js → Timeline-D3kzt1dy.js} +3 -3
- package/dist/{Timeline-WkV4k_we.js.map → Timeline-D3kzt1dy.js.map} +1 -1
- package/dist/{Timeline-CoxW0Ia_.cjs → Timeline-ONU_3gi3.cjs} +2 -2
- package/dist/{Timeline-CoxW0Ia_.cjs.map → Timeline-ONU_3gi3.cjs.map} +1 -1
- package/dist/{Toaster-BynCHvUr.js → Toaster-C6UK_2TB.js} +2 -2
- package/dist/{Toaster-BynCHvUr.js.map → Toaster-C6UK_2TB.js.map} +1 -1
- package/dist/{Toaster-tHet1M-T.cjs → Toaster-Qnsq3guQ.cjs} +2 -2
- package/dist/{Toaster-tHet1M-T.cjs.map → Toaster-Qnsq3guQ.cjs.map} +1 -1
- package/dist/{ToggleButtonGroup-BWd7MOcc.js → ToggleButtonGroup-D9odYMzD.js} +3 -3
- package/dist/{ToggleButtonGroup-BWd7MOcc.js.map → ToggleButtonGroup-D9odYMzD.js.map} +1 -1
- package/dist/{ToggleButtonGroup-DYRLwKKh.cjs → ToggleButtonGroup-M2oj_3mc.cjs} +2 -2
- package/dist/{ToggleButtonGroup-DYRLwKKh.cjs.map → ToggleButtonGroup-M2oj_3mc.cjs.map} +1 -1
- package/dist/{TranslatedFields-DHRFcB3n.js → TranslatedFields-Bo5rZ7so.js} +5 -5
- package/dist/{TranslatedFields-DHRFcB3n.js.map → TranslatedFields-Bo5rZ7so.js.map} +1 -1
- package/dist/{TranslatedFields-B3Gli3TZ.cjs → TranslatedFields-CLMvRpJi.cjs} +2 -2
- package/dist/{TranslatedFields-B3Gli3TZ.cjs.map → TranslatedFields-CLMvRpJi.cjs.map} +1 -1
- package/dist/UserCard-454Kc7JS.js +74 -0
- package/dist/UserCard-454Kc7JS.js.map +1 -0
- package/dist/UserCard-CIjZz5xd.cjs +2 -0
- package/dist/UserCard-CIjZz5xd.cjs.map +1 -0
- 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/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/Checkbox/Checkbox.d.cts +7 -0
- package/dist/components/Checkbox/Checkbox.d.ts +7 -0
- package/dist/components/Checkbox/index.cjs +1 -1
- package/dist/components/Checkbox/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/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/EmptyState/index.cjs +1 -1
- package/dist/components/EmptyState/index.js +1 -1
- 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 +2 -2
- package/dist/components/IconButton/index.cjs +1 -1
- package/dist/components/IconButton/index.js +1 -1
- package/dist/components/List/index.cjs +1 -1
- package/dist/components/List/index.js +1 -1
- package/dist/components/Loader/index.cjs +1 -1
- package/dist/components/Loader/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/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/RemoveDialog/index.cjs +1 -1
- package/dist/components/RemoveDialog/index.js +1 -1
- package/dist/components/RichTextEditor/index.cjs +1 -1
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/components/RootLayout/index.cjs +1 -1
- package/dist/components/RootLayout/index.js +1 -1
- package/dist/components/Select/index.cjs +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/Sidebar/index.cjs +1 -1
- package/dist/components/Sidebar/index.js +1 -1
- package/dist/components/SpeedDial/index.cjs +1 -1
- package/dist/components/SpeedDial/index.js +1 -1
- package/dist/components/Stepper/index.cjs +1 -1
- package/dist/components/Stepper/index.js +1 -1
- package/dist/components/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/UserCard.d.cts +4 -1
- package/dist/components/UserCard/UserCard.d.ts +4 -1
- package/dist/components/UserCard/index.cjs +1 -1
- package/dist/components/UserCard/index.js +1 -1
- package/dist/entries/app.cjs +1 -1
- package/dist/entries/app.js +1 -1
- package/dist/entries/components.cjs +1 -1
- package/dist/entries/components.js +53 -53
- 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 +2 -2
- package/dist/entries/theme.cjs +1 -1
- package/dist/entries/theme.js +1 -1
- package/dist/i18n/messages.d.cts +1 -0
- package/dist/i18n/messages.d.ts +1 -0
- package/dist/icons/names.d.cts +3 -3
- package/dist/icons/names.d.ts +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +56 -56
- package/dist/{messages-FciBtnCL.js → messages-CGHhwf6F.js} +10 -3
- package/dist/messages-CGHhwf6F.js.map +1 -0
- package/dist/messages-DZJyiaf9.cjs +36 -0
- package/dist/messages-DZJyiaf9.cjs.map +1 -0
- package/dist/names-BJnFU_5m.cjs +2 -0
- package/dist/names-BJnFU_5m.cjs.map +1 -0
- package/dist/{names-D8ABK2Wk.js → names-r21QPjcU.js} +3 -2
- package/dist/names-r21QPjcU.js.map +1 -0
- package/package.json +1 -1
- package/dist/Checkbox-DXOzYIAz.cjs +0 -2
- package/dist/Checkbox-DXOzYIAz.cjs.map +0 -1
- package/dist/Checkbox-XKL_Q5qj.js +0 -84
- package/dist/Checkbox-XKL_Q5qj.js.map +0 -1
- package/dist/Icon-CXTl_QAP.cjs +0 -2
- package/dist/Icon-CXTl_QAP.cjs.map +0 -1
- package/dist/Icon-CophpkHo.js.map +0 -1
- package/dist/UserCard-D7U-CLbM.js +0 -74
- package/dist/UserCard-D7U-CLbM.js.map +0 -1
- package/dist/UserCard-GHw2gTx9.cjs +0 -2
- package/dist/UserCard-GHw2gTx9.cjs.map +0 -1
- package/dist/messages-C0YutUM1.cjs +0 -36
- package/dist/messages-C0YutUM1.cjs.map +0 -1
- package/dist/messages-FciBtnCL.js.map +0 -1
- package/dist/names-C2Yj1p3u.cjs +0 -2
- package/dist/names-C2Yj1p3u.cjs.map +0 -1
- package/dist/names-D8ABK2Wk.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const u=require("react/jsx-runtime"),s=require("react"),N=require("clsx"),re=require("./names-
|
|
2
|
-
//# sourceMappingURL=Tabs-
|
|
1
|
+
"use strict";const u=require("react/jsx-runtime"),s=require("react"),N=require("clsx"),re=require("./names-BJnFU_5m.cjs"),se=require("./Icon-BVULqOJD.cjs"),m=require("./ConfigProvider-C7DUWHrb.cjs"),le="_root_1shrp_1",oe="_vertical_1shrp_7",ce="_tablist_1shrp_13",ae="_horizontal_1shrp_17",ie="_fullWidth_1shrp_31",ue="_tab_1shrp_13",de="_underline_1shrp_36",fe="_pill_1shrp_46",be="_inner_1shrp_82",pe="_icon_1shrp_88",he="_label_1shrp_92",_e="_count_1shrp_97",we="_dot_1shrp_113",ve="_error_1shrp_124",ye="_active_1shrp_135",ge="_sm_1shrp_161",xe="_md_1shrp_166",Se="_lg_1shrp_171",Ne="_panel_1shrp_178",r={root:le,vertical:oe,tablist:ce,horizontal:ae,fullWidth:ie,tab:ue,underline:de,pill:fe,inner:be,icon:pe,label:he,count:_e,dot:we,error:ve,active:ye,sm:ge,md:xe,lg:Se,panel:Ne},Re=new Set(re.ICON_NAMES),B=s.createContext(0),Te=s.forwardRef(function({items:f,value:_,defaultValue:R,onChange:b,queryKey:T,pushHistory:I=!1,variant:H="underline",size:j="md",color:M="primary",orientation:d="horizontal",fullWidth:O=!1,autoFocus:F=!1,className:G,style:J,"aria-label":X},Y){var P;const L=s.useId(),E=s.useContext(B),Z=m.useTabsQueryKey(),V=m.useNestedTabQueryKey(),a=T===null?void 0:T??(E===0?Z:V),p=s.useCallback(e=>!!e&&f.some(t=>t.value===e&&!t.disabled),[f]),y=s.useCallback(()=>!a||typeof window>"u"?null:new URLSearchParams(window.location.search).get(a),[a]),z=(P=f.find(e=>!e.disabled))==null?void 0:P.value,[ee,C]=s.useState(()=>{const e=y();return p(e)?e:p(R)?R:z}),K=_!==void 0,k=K?_:ee,l=p(k)?k:z,h=s.useRef(l);h.current=l;const w=s.useRef(b);w.current=b;const g=s.useRef(!1),q=s.useCallback((e,t)=>{if(!a||typeof window>"u")return;const n=new URLSearchParams(window.location.search);if(n.get(a)===e)return;n.set(a,e);const i=`${window.location.pathname}?${n.toString()}${window.location.hash}`;window.history[t?"pushState":"replaceState"](window.history.state,"",i)},[a]),$=e=>{e!==h.current&&(g.current=!0,K||C(e),b==null||b(e))};s.useEffect(()=>{if(!a||typeof window>"u"||l==null)return;const e=g.current&&I;g.current=!1,q(l,e)},[a,l,I,q]),s.useEffect(()=>{if(!a||typeof window>"u")return;const e=()=>{var n;const t=y();p(t)&&t!==h.current&&(_===void 0&&C(t),(n=w.current)==null||n.call(w,t))};return window.addEventListener("popstate",e),()=>window.removeEventListener("popstate",e)},[a,y,p,_]);const x=s.useRef(null),Q=e=>`[data-value="${typeof CSS<"u"&&CSS.escape?CSS.escape(e):e}"]`,A=e=>{var t,n;(n=(t=x.current)==null?void 0:t.querySelector(Q(e)))==null||n.focus()};s.useEffect(()=>{F&&h.current!=null&&A(h.current)},[]),s.useEffect(()=>{if(l==null)return;const e=x.current,t=e==null?void 0:e.querySelector(Q(l));if(!e||!t)return;const n=e.getBoundingClientRect(),i=t.getBoundingClientRect();if(d==="vertical"){const o=i.top-n.top+e.scrollTop,c=o+i.height;o<e.scrollTop?e.scrollTop=o:c>e.scrollTop+e.clientHeight&&(e.scrollTop=c-e.clientHeight)}else{const o=i.left-n.left+e.scrollLeft,c=o+i.width;o<e.scrollLeft?e.scrollLeft=o:c>e.scrollLeft+e.clientWidth&&(e.scrollLeft=c-e.clientWidth)}},[l]);const te=e=>{const t=f.filter(S=>!S.disabled);if(t.length===0)return;const n=d==="horizontal"?"ArrowLeft":"ArrowUp",i=d==="horizontal"?"ArrowRight":"ArrowDown",o=t.findIndex(S=>S.value===l);let c=-1;switch(e.key){case n:c=(o-1+t.length)%t.length;break;case i:c=(o+1)%t.length;break;case"Home":c=0;break;case"End":c=t.length-1;break;default:return}e.preventDefault();const U=t[c].value;$(U),A(U)},ne=e=>typeof e=="string"&&Re.has(e)?u.jsx(se.Icon,{name:e,size:j}):e,v=f.find(e=>e.value===l),D=`${L}-panel`,W=e=>`${L}-tab-${e}`;return u.jsxs("div",{ref:Y,className:N.clsx(r.root,r[d],G),style:J,children:[u.jsx("div",{ref:x,role:"tablist","aria-label":X,"aria-orientation":d,className:N.clsx(r.tablist,r[H],r[j],r[d],O&&d==="horizontal"&&r.fullWidth),onKeyDown:te,children:f.map(e=>{const t=e.value===l,n=M,i=ne(e.icon),o=e.badge!=null&&e.badge!==0,c=!o&&(e.dot||e.error);return u.jsx("button",{type:"button",role:"tab","data-value":e.value,id:W(e.value),"aria-selected":t,"aria-label":e.label==null?e.ariaLabel??e.value:e.ariaLabel,"aria-controls":t&&e.content!=null?D:void 0,"aria-disabled":e.disabled||void 0,disabled:e.disabled,tabIndex:t?0:-1,className:N.clsx(r.tab,t&&r.active,e.error&&r.error),style:{"--tz-btn-rgb":`var(--tz-color-${n}-rgb)`,"--tz-btn-on":`var(--tz-color-${n}-contrast, #fff)`},onClick:()=>$(e.value),children:u.jsxs("span",{className:r.inner,children:[i!=null&&u.jsx("span",{className:r.icon,children:i}),e.label!=null&&u.jsx("span",{className:r.label,children:e.label}),o&&u.jsx("span",{className:r.count,children:typeof e.badge=="number"&&e.badge>99?"99+":e.badge}),c&&u.jsx("span",{className:r.dot,"aria-hidden":"true"})]})},e.value)})}),(v==null?void 0:v.content)!=null&&l!=null&&u.jsx("div",{role:"tabpanel",id:D,"aria-labelledby":W(l),tabIndex:0,className:r.panel,children:u.jsx(B.Provider,{value:E+1,children:v.content})})]})});exports.Tabs=Te;
|
|
2
|
+
//# sourceMappingURL=Tabs-BtcJ2jBl.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs-ozklGWmX.cjs","sources":["../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useNestedTabQueryKey, useTabsQueryKey, type ThemeColor } from '../../theme'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { Icon } from '../Icon'\nimport styles from './Tabs.module.css'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/**\n * Tracks `<Tabs>` nesting depth via context: a top-level strip is depth `0`, a strip rendered inside\n * another tab's panel is `1`, and so on. Used to pick the right default URL query key (`tabQueryKey` at\n * depth `0`, else `nestedTabQueryKey`) so nested strips don't collide on the same param. Default `0`.\n */\nconst TabsDepthContext = createContext(0)\n\nexport type TabsVariant = 'underline' | 'pill'\nexport type TabsSize = 'sm' | 'md' | 'lg'\nexport type TabsOrientation = 'horizontal' | 'vertical'\n\nexport interface TabItem {\n /** Unique value — also what's written to the URL query and passed to `onChange`. */\n value: string\n /** Tab label. */\n label?: ReactNode\n /** Accessible name — required for an icon-only tab (no visible `label`); falls back to `value`. */\n ariaLabel?: string\n /** Leading icon — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Disables the tab (not selectable; skipped by keyboard nav). */\n disabled?: boolean\n /** Marks the tab invalid — shows a small **red** dot (e.g. its section failed validation). No full-tab tint. */\n error?: boolean\n /** Small dot indicator in the tab color (e.g. unread / notification). `error` shows a red one instead. */\n dot?: boolean\n /** Count / text indicator (rendered with `Badge`); wins over `dot`. */\n badge?: number | string\n /** Panel content rendered below (or beside) the strip while this tab is active. Optional. */\n content?: ReactNode\n}\n\nexport interface TabsProps {\n /** The tabs. */\n items: TabItem[]\n /** Controlled active value. */\n value?: string\n /**\n * Initial active value (uncontrolled). Falls back to the URL query (when URL sync is active and the\n * param is present) and otherwise the first enabled tab.\n */\n defaultValue?: string\n /** Fires with the next active value. */\n onChange?: (value: string) => void\n /**\n * URL query param name to sync the active tab to (e.g. `'tab'` → `?tab=general`), so a page refresh\n * restores it. **Defaults to the configured `keys.tabQueryKey` (else `'tab'`)** at the top level, and\n * `keys.nestedTabQueryKey` (else `'nestedTab'`) for a strip **nested** inside another tab's panel — so\n * the two don't collide (auto-applied by nesting depth). Every tab strip URL-syncs out of the box.\n * Pass **`null`** to opt out (state only). For 3+ nesting levels, set distinct keys explicitly.\n */\n queryKey?: string | null\n /**\n * Push a history entry on each tab change, so the browser **Back** button returns to the previous\n * tab. Defaults to `false` — tab changes **replace** the URL, so Back leaves the page instead of\n * stepping through tabs (and `popstate` still restores a tab when one is in the query).\n */\n pushHistory?: boolean\n /** Visual style. Defaults to `'underline'`. */\n variant?: TabsVariant\n /** Preset size. Defaults to `'md'`. */\n size?: TabsSize\n /** Theme palette token tinting the active tab. Defaults to `'primary'`. */\n color?: ThemeColor\n /** Strip direction. Defaults to `'horizontal'`. */\n orientation?: TabsOrientation\n /** Stretch the tabs to fill the strip equally (horizontal only). */\n fullWidth?: boolean\n /** Focus the active tab on mount (e.g. when the strip lives inside a popover that just opened). */\n autoFocus?: boolean\n /** Accessible label for the tablist. */\n 'aria-label'?: string\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A tab strip with optional panels. Data-driven via `items` (each: `label`, `icon`, `disabled`,\n * `error`, `dot`/`badge` via `Badge`, optional `content`). Controlled (`value` + `onChange`) or\n * uncontrolled (`defaultValue`). The active tab **syncs to the URL query by default** under\n * **`queryKey`** (defaults to the configured `keys.tabQueryKey`, else `'tab'` — and `keys.nestedTabQueryKey`,\n * else `'nestedTab'`, for a strip nested in another tab's panel: `?<queryKey>=<value>`) so a\n * refresh restores it — pass **`queryKey={null}`** to opt out. Tab changes **replace** the URL by\n * default (so Back doesn't step through tabs); pass **`pushHistory`** to make Back navigate tabs. Full\n * keyboard support (Arrows / Home / End, roving tabindex) and `role=\"tablist\"`/`tab`/`tabpanel` a11y.\n */\nexport const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(\n {\n items,\n value,\n defaultValue,\n onChange,\n queryKey,\n pushHistory = false,\n variant = 'underline',\n size = 'md',\n color = 'primary',\n orientation = 'horizontal',\n fullWidth = false,\n autoFocus = false,\n className,\n style,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const reactId = useId()\n\n // resolve the URL-sync key: an explicit `null` opts out (state only); omitting it falls back to the\n // configured default — `keys.tabQueryKey` for a top-level strip, `keys.nestedTabQueryKey` for one\n // nested inside another tab's panel (by depth) — so nested strips don't collide on the same param.\n const depth = useContext(TabsDepthContext)\n const tabQueryKey = useTabsQueryKey()\n const nestedTabQueryKey = useNestedTabQueryKey()\n const configQueryKey = depth === 0 ? tabQueryKey : nestedTabQueryKey\n const syncKey = queryKey === null ? undefined : (queryKey ?? configQueryKey)\n\n const isSelectable = useCallback(\n (v: string | null | undefined): v is string =>\n !!v && items.some((i) => i.value === v && !i.disabled),\n [items],\n )\n\n const readQuery = useCallback((): string | null => {\n if (!syncKey || typeof window === 'undefined') return null\n return new URLSearchParams(window.location.search).get(syncKey)\n }, [syncKey])\n\n // undefined when every tab is disabled — better than defaulting to a disabled tab (nothing active)\n const firstEnabled = items.find((i) => !i.disabled)?.value\n\n const [internal, setInternal] = useState<string | undefined>(() => {\n const q = readQuery()\n if (isSelectable(q)) return q\n return isSelectable(defaultValue) ? defaultValue : firstEnabled\n })\n const isControlled = value !== undefined\n const raw = isControlled ? value : internal\n // clamp to a present, enabled tab — guarantees a focusable roving tabstop + a rendered panel (no\n // keyboard trap) and keeps a bogus/disabled value out of the URL; falls back to the first enabled tab\n const active = isSelectable(raw) ? raw : firstEnabled\n\n // keep the latest active / onChange / push-intent for the stable effects + popstate listener\n const activeRef = useRef(active)\n activeRef.current = active\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const pushIntent = useRef(false)\n\n const writeQuery = useCallback(\n (next: string, push: boolean) => {\n if (!syncKey || typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n if (params.get(syncKey) === next) return\n params.set(syncKey, next)\n const url = `${window.location.pathname}?${params.toString()}${window.location.hash}`\n window.history[push ? 'pushState' : 'replaceState'](window.history.state, '', url)\n },\n [syncKey],\n )\n\n const select = (next: string) => {\n if (next === activeRef.current) return\n pushIntent.current = true\n if (!isControlled) setInternal(next)\n onChange?.(next)\n }\n\n // mirror the *resolved* active tab into the URL whenever it changes (and on mount = canonicalize), so\n // the URL never holds a bogus value and a controlled value-change still syncs. A user-driven change\n // `push`es when `pushHistory` (Back walks tabs); programmatic / popstate changes just `replace`.\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined' || active == null) return\n const push = pushIntent.current && pushHistory\n pushIntent.current = false\n writeQuery(active, push)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [syncKey, active, pushHistory, writeQuery])\n\n // Back/Forward → restore the tab from the query\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined') return\n const onPopState = () => {\n const q = readQuery()\n if (isSelectable(q) && q !== activeRef.current) {\n if (value === undefined) setInternal(q)\n onChangeRef.current?.(q)\n }\n }\n window.addEventListener('popstate', onPopState)\n return () => window.removeEventListener('popstate', onPopState)\n }, [syncKey, readQuery, isSelectable, value])\n\n const tablistRef = useRef<HTMLDivElement | null>(null)\n const tabSelector = (v: string) =>\n `[data-value=\"${typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(v) : v}\"]`\n const focusTab = (v: string) => {\n tablistRef.current?.querySelector<HTMLElement>(tabSelector(v))?.focus()\n }\n\n // optionally move focus onto the active tab once, on mount (e.g. inside a popover that just opened)\n useEffect(() => {\n if (autoFocus && activeRef.current != null) focusTab(activeRef.current)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // keep the active tab in view when the strip overflows — by moving the tablist's OWN scroll offset\n // only. (scrollIntoView would also scroll every scrollable ancestor — i.e. the page — yanking a\n // below-the-fold strip's section into view on mount.)\n useEffect(() => {\n if (active == null) return\n const list = tablistRef.current\n const el = list?.querySelector<HTMLElement>(tabSelector(active))\n if (!list || !el) return\n const listRect = list.getBoundingClientRect()\n const elRect = el.getBoundingClientRect()\n if (orientation === 'vertical') {\n const top = elRect.top - listRect.top + list.scrollTop\n const bottom = top + elRect.height\n if (top < list.scrollTop) list.scrollTop = top\n else if (bottom > list.scrollTop + list.clientHeight)\n list.scrollTop = bottom - list.clientHeight\n } else {\n const left = elRect.left - listRect.left + list.scrollLeft\n const right = left + elRect.width\n if (left < list.scrollLeft) list.scrollLeft = left\n else if (right > list.scrollLeft + list.clientWidth)\n list.scrollLeft = right - list.clientWidth\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const enabled = items.filter((i) => !i.disabled)\n if (enabled.length === 0) return\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n const current = enabled.findIndex((i) => i.value === active)\n let target = -1\n switch (event.key) {\n case prevKey:\n target = (current - 1 + enabled.length) % enabled.length\n break\n case nextKey:\n target = (current + 1) % enabled.length\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = enabled.length - 1\n break\n default:\n return\n }\n event.preventDefault()\n const next = enabled[target].value\n select(next)\n focusTab(next)\n }\n\n const renderIcon = (icon: TabItem['icon']) =>\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n\n const activeItem = items.find((i) => i.value === active)\n const panelId = `${reactId}-panel`\n const tabId = (v: string) => `${reactId}-tab-${v}`\n\n return (\n <div ref={ref} className={clsx(styles.root, styles[orientation], className)} style={style}>\n <div\n ref={tablistRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={orientation}\n className={clsx(\n styles.tablist,\n styles[variant],\n styles[size],\n styles[orientation],\n fullWidth && orientation === 'horizontal' && styles.fullWidth,\n )}\n onKeyDown={handleKeyDown}\n >\n {items.map((item) => {\n const selected = item.value === active\n // the tab keeps its theme color; `error` shows up only as a red dot, not a full-tab tint\n const tint = color\n const icon = renderIcon(item.icon)\n const hasCount = item.badge != null && item.badge !== 0\n // a dot shows for an explicit `dot` (tinted) or an `error` tab (red — see CSS); count wins\n const showDot = !hasCount && (item.dot || item.error)\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n data-value={item.value}\n id={tabId(item.value)}\n aria-selected={selected}\n aria-label={item.label == null ? (item.ariaLabel ?? item.value) : item.ariaLabel}\n aria-controls={selected && item.content != null ? panelId : undefined}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n tabIndex={selected ? 0 : -1}\n className={clsx(styles.tab, selected && styles.active, item.error && styles.error)}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${tint}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${tint}-contrast, #fff)`,\n } as CSSProperties\n }\n onClick={() => select(item.value)}\n >\n <span className={styles.inner}>\n {icon != null && <span className={styles.icon}>{icon}</span>}\n {item.label != null && <span className={styles.label}>{item.label}</span>}\n {hasCount && (\n <span className={styles.count}>\n {typeof item.badge === 'number' && item.badge > 99 ? '99+' : item.badge}\n </span>\n )}\n {showDot && <span className={styles.dot} aria-hidden=\"true\" />}\n </span>\n </button>\n )\n })}\n </div>\n\n {activeItem?.content != null && active != null && (\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={tabId(active)}\n tabIndex={0}\n className={styles.panel}\n >\n {/* a <Tabs> rendered in here is one level deeper → picks the nested query key by default */}\n <TabsDepthContext.Provider value={depth + 1}>\n {activeItem.content}\n </TabsDepthContext.Provider>\n </div>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","TabsDepthContext","createContext","Tabs","forwardRef","items","value","defaultValue","onChange","queryKey","pushHistory","variant","size","color","orientation","fullWidth","autoFocus","className","style","ariaLabel","ref","reactId","useId","depth","useContext","tabQueryKey","useTabsQueryKey","nestedTabQueryKey","useNestedTabQueryKey","syncKey","isSelectable","useCallback","v","i","readQuery","firstEnabled","_a","internal","setInternal","useState","q","isControlled","raw","active","activeRef","useRef","onChangeRef","pushIntent","writeQuery","next","push","params","url","select","useEffect","onPopState","tablistRef","tabSelector","focusTab","_b","list","el","listRect","elRect","top","bottom","left","right","handleKeyDown","event","enabled","prevKey","nextKey","current","target","renderIcon","icon","jsx","Icon","activeItem","panelId","tabId","jsxs","clsx","styles","item","selected","tint","hasCount","showDot"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Tabs-BtcJ2jBl.cjs","sources":["../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useNestedTabQueryKey, useTabsQueryKey, type ThemeColor } from '../../theme'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { Icon } from '../Icon'\nimport styles from './Tabs.module.css'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/**\n * Tracks `<Tabs>` nesting depth via context: a top-level strip is depth `0`, a strip rendered inside\n * another tab's panel is `1`, and so on. Used to pick the right default URL query key (`tabQueryKey` at\n * depth `0`, else `nestedTabQueryKey`) so nested strips don't collide on the same param. Default `0`.\n */\nconst TabsDepthContext = createContext(0)\n\nexport type TabsVariant = 'underline' | 'pill'\nexport type TabsSize = 'sm' | 'md' | 'lg'\nexport type TabsOrientation = 'horizontal' | 'vertical'\n\nexport interface TabItem {\n /** Unique value — also what's written to the URL query and passed to `onChange`. */\n value: string\n /** Tab label. */\n label?: ReactNode\n /** Accessible name — required for an icon-only tab (no visible `label`); falls back to `value`. */\n ariaLabel?: string\n /** Leading icon — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Disables the tab (not selectable; skipped by keyboard nav). */\n disabled?: boolean\n /** Marks the tab invalid — shows a small **red** dot (e.g. its section failed validation). No full-tab tint. */\n error?: boolean\n /** Small dot indicator in the tab color (e.g. unread / notification). `error` shows a red one instead. */\n dot?: boolean\n /** Count / text indicator (rendered with `Badge`); wins over `dot`. */\n badge?: number | string\n /** Panel content rendered below (or beside) the strip while this tab is active. Optional. */\n content?: ReactNode\n}\n\nexport interface TabsProps {\n /** The tabs. */\n items: TabItem[]\n /** Controlled active value. */\n value?: string\n /**\n * Initial active value (uncontrolled). Falls back to the URL query (when URL sync is active and the\n * param is present) and otherwise the first enabled tab.\n */\n defaultValue?: string\n /** Fires with the next active value. */\n onChange?: (value: string) => void\n /**\n * URL query param name to sync the active tab to (e.g. `'tab'` → `?tab=general`), so a page refresh\n * restores it. **Defaults to the configured `keys.tabQueryKey` (else `'tab'`)** at the top level, and\n * `keys.nestedTabQueryKey` (else `'nestedTab'`) for a strip **nested** inside another tab's panel — so\n * the two don't collide (auto-applied by nesting depth). Every tab strip URL-syncs out of the box.\n * Pass **`null`** to opt out (state only). For 3+ nesting levels, set distinct keys explicitly.\n */\n queryKey?: string | null\n /**\n * Push a history entry on each tab change, so the browser **Back** button returns to the previous\n * tab. Defaults to `false` — tab changes **replace** the URL, so Back leaves the page instead of\n * stepping through tabs (and `popstate` still restores a tab when one is in the query).\n */\n pushHistory?: boolean\n /** Visual style. Defaults to `'underline'`. */\n variant?: TabsVariant\n /** Preset size. Defaults to `'md'`. */\n size?: TabsSize\n /** Theme palette token tinting the active tab. Defaults to `'primary'`. */\n color?: ThemeColor\n /** Strip direction. Defaults to `'horizontal'`. */\n orientation?: TabsOrientation\n /** Stretch the tabs to fill the strip equally (horizontal only). */\n fullWidth?: boolean\n /** Focus the active tab on mount (e.g. when the strip lives inside a popover that just opened). */\n autoFocus?: boolean\n /** Accessible label for the tablist. */\n 'aria-label'?: string\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A tab strip with optional panels. Data-driven via `items` (each: `label`, `icon`, `disabled`,\n * `error`, `dot`/`badge` via `Badge`, optional `content`). Controlled (`value` + `onChange`) or\n * uncontrolled (`defaultValue`). The active tab **syncs to the URL query by default** under\n * **`queryKey`** (defaults to the configured `keys.tabQueryKey`, else `'tab'` — and `keys.nestedTabQueryKey`,\n * else `'nestedTab'`, for a strip nested in another tab's panel: `?<queryKey>=<value>`) so a\n * refresh restores it — pass **`queryKey={null}`** to opt out. Tab changes **replace** the URL by\n * default (so Back doesn't step through tabs); pass **`pushHistory`** to make Back navigate tabs. Full\n * keyboard support (Arrows / Home / End, roving tabindex) and `role=\"tablist\"`/`tab`/`tabpanel` a11y.\n */\nexport const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(\n {\n items,\n value,\n defaultValue,\n onChange,\n queryKey,\n pushHistory = false,\n variant = 'underline',\n size = 'md',\n color = 'primary',\n orientation = 'horizontal',\n fullWidth = false,\n autoFocus = false,\n className,\n style,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const reactId = useId()\n\n // resolve the URL-sync key: an explicit `null` opts out (state only); omitting it falls back to the\n // configured default — `keys.tabQueryKey` for a top-level strip, `keys.nestedTabQueryKey` for one\n // nested inside another tab's panel (by depth) — so nested strips don't collide on the same param.\n const depth = useContext(TabsDepthContext)\n const tabQueryKey = useTabsQueryKey()\n const nestedTabQueryKey = useNestedTabQueryKey()\n const configQueryKey = depth === 0 ? tabQueryKey : nestedTabQueryKey\n const syncKey = queryKey === null ? undefined : (queryKey ?? configQueryKey)\n\n const isSelectable = useCallback(\n (v: string | null | undefined): v is string =>\n !!v && items.some((i) => i.value === v && !i.disabled),\n [items],\n )\n\n const readQuery = useCallback((): string | null => {\n if (!syncKey || typeof window === 'undefined') return null\n return new URLSearchParams(window.location.search).get(syncKey)\n }, [syncKey])\n\n // undefined when every tab is disabled — better than defaulting to a disabled tab (nothing active)\n const firstEnabled = items.find((i) => !i.disabled)?.value\n\n const [internal, setInternal] = useState<string | undefined>(() => {\n const q = readQuery()\n if (isSelectable(q)) return q\n return isSelectable(defaultValue) ? defaultValue : firstEnabled\n })\n const isControlled = value !== undefined\n const raw = isControlled ? value : internal\n // clamp to a present, enabled tab — guarantees a focusable roving tabstop + a rendered panel (no\n // keyboard trap) and keeps a bogus/disabled value out of the URL; falls back to the first enabled tab\n const active = isSelectable(raw) ? raw : firstEnabled\n\n // keep the latest active / onChange / push-intent for the stable effects + popstate listener\n const activeRef = useRef(active)\n activeRef.current = active\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const pushIntent = useRef(false)\n\n const writeQuery = useCallback(\n (next: string, push: boolean) => {\n if (!syncKey || typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n if (params.get(syncKey) === next) return\n params.set(syncKey, next)\n const url = `${window.location.pathname}?${params.toString()}${window.location.hash}`\n window.history[push ? 'pushState' : 'replaceState'](window.history.state, '', url)\n },\n [syncKey],\n )\n\n const select = (next: string) => {\n if (next === activeRef.current) return\n pushIntent.current = true\n if (!isControlled) setInternal(next)\n onChange?.(next)\n }\n\n // mirror the *resolved* active tab into the URL whenever it changes (and on mount = canonicalize), so\n // the URL never holds a bogus value and a controlled value-change still syncs. A user-driven change\n // `push`es when `pushHistory` (Back walks tabs); programmatic / popstate changes just `replace`.\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined' || active == null) return\n const push = pushIntent.current && pushHistory\n pushIntent.current = false\n writeQuery(active, push)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [syncKey, active, pushHistory, writeQuery])\n\n // Back/Forward → restore the tab from the query\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined') return\n const onPopState = () => {\n const q = readQuery()\n if (isSelectable(q) && q !== activeRef.current) {\n if (value === undefined) setInternal(q)\n onChangeRef.current?.(q)\n }\n }\n window.addEventListener('popstate', onPopState)\n return () => window.removeEventListener('popstate', onPopState)\n }, [syncKey, readQuery, isSelectable, value])\n\n const tablistRef = useRef<HTMLDivElement | null>(null)\n const tabSelector = (v: string) =>\n `[data-value=\"${typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(v) : v}\"]`\n const focusTab = (v: string) => {\n tablistRef.current?.querySelector<HTMLElement>(tabSelector(v))?.focus()\n }\n\n // optionally move focus onto the active tab once, on mount (e.g. inside a popover that just opened)\n useEffect(() => {\n if (autoFocus && activeRef.current != null) focusTab(activeRef.current)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // keep the active tab in view when the strip overflows — by moving the tablist's OWN scroll offset\n // only. (scrollIntoView would also scroll every scrollable ancestor — i.e. the page — yanking a\n // below-the-fold strip's section into view on mount.)\n useEffect(() => {\n if (active == null) return\n const list = tablistRef.current\n const el = list?.querySelector<HTMLElement>(tabSelector(active))\n if (!list || !el) return\n const listRect = list.getBoundingClientRect()\n const elRect = el.getBoundingClientRect()\n if (orientation === 'vertical') {\n const top = elRect.top - listRect.top + list.scrollTop\n const bottom = top + elRect.height\n if (top < list.scrollTop) list.scrollTop = top\n else if (bottom > list.scrollTop + list.clientHeight)\n list.scrollTop = bottom - list.clientHeight\n } else {\n const left = elRect.left - listRect.left + list.scrollLeft\n const right = left + elRect.width\n if (left < list.scrollLeft) list.scrollLeft = left\n else if (right > list.scrollLeft + list.clientWidth)\n list.scrollLeft = right - list.clientWidth\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const enabled = items.filter((i) => !i.disabled)\n if (enabled.length === 0) return\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n const current = enabled.findIndex((i) => i.value === active)\n let target = -1\n switch (event.key) {\n case prevKey:\n target = (current - 1 + enabled.length) % enabled.length\n break\n case nextKey:\n target = (current + 1) % enabled.length\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = enabled.length - 1\n break\n default:\n return\n }\n event.preventDefault()\n const next = enabled[target].value\n select(next)\n focusTab(next)\n }\n\n const renderIcon = (icon: TabItem['icon']) =>\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n\n const activeItem = items.find((i) => i.value === active)\n const panelId = `${reactId}-panel`\n const tabId = (v: string) => `${reactId}-tab-${v}`\n\n return (\n <div ref={ref} className={clsx(styles.root, styles[orientation], className)} style={style}>\n <div\n ref={tablistRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={orientation}\n className={clsx(\n styles.tablist,\n styles[variant],\n styles[size],\n styles[orientation],\n fullWidth && orientation === 'horizontal' && styles.fullWidth,\n )}\n onKeyDown={handleKeyDown}\n >\n {items.map((item) => {\n const selected = item.value === active\n // the tab keeps its theme color; `error` shows up only as a red dot, not a full-tab tint\n const tint = color\n const icon = renderIcon(item.icon)\n const hasCount = item.badge != null && item.badge !== 0\n // a dot shows for an explicit `dot` (tinted) or an `error` tab (red — see CSS); count wins\n const showDot = !hasCount && (item.dot || item.error)\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n data-value={item.value}\n id={tabId(item.value)}\n aria-selected={selected}\n aria-label={item.label == null ? (item.ariaLabel ?? item.value) : item.ariaLabel}\n aria-controls={selected && item.content != null ? panelId : undefined}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n tabIndex={selected ? 0 : -1}\n className={clsx(styles.tab, selected && styles.active, item.error && styles.error)}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${tint}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${tint}-contrast, #fff)`,\n } as CSSProperties\n }\n onClick={() => select(item.value)}\n >\n <span className={styles.inner}>\n {icon != null && <span className={styles.icon}>{icon}</span>}\n {item.label != null && <span className={styles.label}>{item.label}</span>}\n {hasCount && (\n <span className={styles.count}>\n {typeof item.badge === 'number' && item.badge > 99 ? '99+' : item.badge}\n </span>\n )}\n {showDot && <span className={styles.dot} aria-hidden=\"true\" />}\n </span>\n </button>\n )\n })}\n </div>\n\n {activeItem?.content != null && active != null && (\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={tabId(active)}\n tabIndex={0}\n className={styles.panel}\n >\n {/* a <Tabs> rendered in here is one level deeper → picks the nested query key by default */}\n <TabsDepthContext.Provider value={depth + 1}>\n {activeItem.content}\n </TabsDepthContext.Provider>\n </div>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","TabsDepthContext","createContext","Tabs","forwardRef","items","value","defaultValue","onChange","queryKey","pushHistory","variant","size","color","orientation","fullWidth","autoFocus","className","style","ariaLabel","ref","reactId","useId","depth","useContext","tabQueryKey","useTabsQueryKey","nestedTabQueryKey","useNestedTabQueryKey","syncKey","isSelectable","useCallback","v","i","readQuery","firstEnabled","_a","internal","setInternal","useState","q","isControlled","raw","active","activeRef","useRef","onChangeRef","pushIntent","writeQuery","next","push","params","url","select","useEffect","onPopState","tablistRef","tabSelector","focusTab","_b","list","el","listRect","elRect","top","bottom","left","right","handleKeyDown","event","enabled","prevKey","nextKey","current","target","renderIcon","icon","jsx","Icon","activeItem","panelId","tabId","jsxs","clsx","styles","item","selected","tint","hasCount","showDot"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsxs as H, jsx as i } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as le, useId as se, useContext as ae, useCallback as I, useState as ce, useRef as y, useEffect as v, createContext as ie } from "react";
|
|
3
3
|
import { clsx as m } from "clsx";
|
|
4
|
-
import { a as de } from "./names-
|
|
5
|
-
import { I as ue } from "./Icon-
|
|
6
|
-
import { l as fe, i as pe } from "./ConfigProvider-
|
|
4
|
+
import { a as de } from "./names-r21QPjcU.js";
|
|
5
|
+
import { I as ue } from "./Icon-DaTvzLBu.js";
|
|
6
|
+
import { l as fe, i as pe } from "./ConfigProvider-DT0yrgmd.js";
|
|
7
7
|
const be = "_root_1shrp_1", he = "_vertical_1shrp_7", _e = "_tablist_1shrp_13", we = "_horizontal_1shrp_17", ye = "_fullWidth_1shrp_31", ve = "_tab_1shrp_13", ge = "_underline_1shrp_36", Se = "_pill_1shrp_46", Ne = "_inner_1shrp_82", Te = "_icon_1shrp_88", Ie = "_label_1shrp_92", me = "_count_1shrp_97", Le = "_dot_1shrp_113", ze = "_error_1shrp_124", Ke = "_active_1shrp_135", Re = "_sm_1shrp_161", xe = "_md_1shrp_166", $e = "_lg_1shrp_171", Ee = "_panel_1shrp_178", r = {
|
|
8
8
|
root: be,
|
|
9
9
|
vertical: he,
|
|
@@ -187,4 +187,4 @@ const be = "_root_1shrp_1", he = "_vertical_1shrp_7", _e = "_tablist_1shrp_13",
|
|
|
187
187
|
export {
|
|
188
188
|
je as T
|
|
189
189
|
};
|
|
190
|
-
//# sourceMappingURL=Tabs-
|
|
190
|
+
//# sourceMappingURL=Tabs-DJMfAUni.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs-B0mWCNaC.js","sources":["../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useNestedTabQueryKey, useTabsQueryKey, type ThemeColor } from '../../theme'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { Icon } from '../Icon'\nimport styles from './Tabs.module.css'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/**\n * Tracks `<Tabs>` nesting depth via context: a top-level strip is depth `0`, a strip rendered inside\n * another tab's panel is `1`, and so on. Used to pick the right default URL query key (`tabQueryKey` at\n * depth `0`, else `nestedTabQueryKey`) so nested strips don't collide on the same param. Default `0`.\n */\nconst TabsDepthContext = createContext(0)\n\nexport type TabsVariant = 'underline' | 'pill'\nexport type TabsSize = 'sm' | 'md' | 'lg'\nexport type TabsOrientation = 'horizontal' | 'vertical'\n\nexport interface TabItem {\n /** Unique value — also what's written to the URL query and passed to `onChange`. */\n value: string\n /** Tab label. */\n label?: ReactNode\n /** Accessible name — required for an icon-only tab (no visible `label`); falls back to `value`. */\n ariaLabel?: string\n /** Leading icon — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Disables the tab (not selectable; skipped by keyboard nav). */\n disabled?: boolean\n /** Marks the tab invalid — shows a small **red** dot (e.g. its section failed validation). No full-tab tint. */\n error?: boolean\n /** Small dot indicator in the tab color (e.g. unread / notification). `error` shows a red one instead. */\n dot?: boolean\n /** Count / text indicator (rendered with `Badge`); wins over `dot`. */\n badge?: number | string\n /** Panel content rendered below (or beside) the strip while this tab is active. Optional. */\n content?: ReactNode\n}\n\nexport interface TabsProps {\n /** The tabs. */\n items: TabItem[]\n /** Controlled active value. */\n value?: string\n /**\n * Initial active value (uncontrolled). Falls back to the URL query (when URL sync is active and the\n * param is present) and otherwise the first enabled tab.\n */\n defaultValue?: string\n /** Fires with the next active value. */\n onChange?: (value: string) => void\n /**\n * URL query param name to sync the active tab to (e.g. `'tab'` → `?tab=general`), so a page refresh\n * restores it. **Defaults to the configured `keys.tabQueryKey` (else `'tab'`)** at the top level, and\n * `keys.nestedTabQueryKey` (else `'nestedTab'`) for a strip **nested** inside another tab's panel — so\n * the two don't collide (auto-applied by nesting depth). Every tab strip URL-syncs out of the box.\n * Pass **`null`** to opt out (state only). For 3+ nesting levels, set distinct keys explicitly.\n */\n queryKey?: string | null\n /**\n * Push a history entry on each tab change, so the browser **Back** button returns to the previous\n * tab. Defaults to `false` — tab changes **replace** the URL, so Back leaves the page instead of\n * stepping through tabs (and `popstate` still restores a tab when one is in the query).\n */\n pushHistory?: boolean\n /** Visual style. Defaults to `'underline'`. */\n variant?: TabsVariant\n /** Preset size. Defaults to `'md'`. */\n size?: TabsSize\n /** Theme palette token tinting the active tab. Defaults to `'primary'`. */\n color?: ThemeColor\n /** Strip direction. Defaults to `'horizontal'`. */\n orientation?: TabsOrientation\n /** Stretch the tabs to fill the strip equally (horizontal only). */\n fullWidth?: boolean\n /** Focus the active tab on mount (e.g. when the strip lives inside a popover that just opened). */\n autoFocus?: boolean\n /** Accessible label for the tablist. */\n 'aria-label'?: string\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A tab strip with optional panels. Data-driven via `items` (each: `label`, `icon`, `disabled`,\n * `error`, `dot`/`badge` via `Badge`, optional `content`). Controlled (`value` + `onChange`) or\n * uncontrolled (`defaultValue`). The active tab **syncs to the URL query by default** under\n * **`queryKey`** (defaults to the configured `keys.tabQueryKey`, else `'tab'` — and `keys.nestedTabQueryKey`,\n * else `'nestedTab'`, for a strip nested in another tab's panel: `?<queryKey>=<value>`) so a\n * refresh restores it — pass **`queryKey={null}`** to opt out. Tab changes **replace** the URL by\n * default (so Back doesn't step through tabs); pass **`pushHistory`** to make Back navigate tabs. Full\n * keyboard support (Arrows / Home / End, roving tabindex) and `role=\"tablist\"`/`tab`/`tabpanel` a11y.\n */\nexport const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(\n {\n items,\n value,\n defaultValue,\n onChange,\n queryKey,\n pushHistory = false,\n variant = 'underline',\n size = 'md',\n color = 'primary',\n orientation = 'horizontal',\n fullWidth = false,\n autoFocus = false,\n className,\n style,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const reactId = useId()\n\n // resolve the URL-sync key: an explicit `null` opts out (state only); omitting it falls back to the\n // configured default — `keys.tabQueryKey` for a top-level strip, `keys.nestedTabQueryKey` for one\n // nested inside another tab's panel (by depth) — so nested strips don't collide on the same param.\n const depth = useContext(TabsDepthContext)\n const tabQueryKey = useTabsQueryKey()\n const nestedTabQueryKey = useNestedTabQueryKey()\n const configQueryKey = depth === 0 ? tabQueryKey : nestedTabQueryKey\n const syncKey = queryKey === null ? undefined : (queryKey ?? configQueryKey)\n\n const isSelectable = useCallback(\n (v: string | null | undefined): v is string =>\n !!v && items.some((i) => i.value === v && !i.disabled),\n [items],\n )\n\n const readQuery = useCallback((): string | null => {\n if (!syncKey || typeof window === 'undefined') return null\n return new URLSearchParams(window.location.search).get(syncKey)\n }, [syncKey])\n\n // undefined when every tab is disabled — better than defaulting to a disabled tab (nothing active)\n const firstEnabled = items.find((i) => !i.disabled)?.value\n\n const [internal, setInternal] = useState<string | undefined>(() => {\n const q = readQuery()\n if (isSelectable(q)) return q\n return isSelectable(defaultValue) ? defaultValue : firstEnabled\n })\n const isControlled = value !== undefined\n const raw = isControlled ? value : internal\n // clamp to a present, enabled tab — guarantees a focusable roving tabstop + a rendered panel (no\n // keyboard trap) and keeps a bogus/disabled value out of the URL; falls back to the first enabled tab\n const active = isSelectable(raw) ? raw : firstEnabled\n\n // keep the latest active / onChange / push-intent for the stable effects + popstate listener\n const activeRef = useRef(active)\n activeRef.current = active\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const pushIntent = useRef(false)\n\n const writeQuery = useCallback(\n (next: string, push: boolean) => {\n if (!syncKey || typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n if (params.get(syncKey) === next) return\n params.set(syncKey, next)\n const url = `${window.location.pathname}?${params.toString()}${window.location.hash}`\n window.history[push ? 'pushState' : 'replaceState'](window.history.state, '', url)\n },\n [syncKey],\n )\n\n const select = (next: string) => {\n if (next === activeRef.current) return\n pushIntent.current = true\n if (!isControlled) setInternal(next)\n onChange?.(next)\n }\n\n // mirror the *resolved* active tab into the URL whenever it changes (and on mount = canonicalize), so\n // the URL never holds a bogus value and a controlled value-change still syncs. A user-driven change\n // `push`es when `pushHistory` (Back walks tabs); programmatic / popstate changes just `replace`.\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined' || active == null) return\n const push = pushIntent.current && pushHistory\n pushIntent.current = false\n writeQuery(active, push)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [syncKey, active, pushHistory, writeQuery])\n\n // Back/Forward → restore the tab from the query\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined') return\n const onPopState = () => {\n const q = readQuery()\n if (isSelectable(q) && q !== activeRef.current) {\n if (value === undefined) setInternal(q)\n onChangeRef.current?.(q)\n }\n }\n window.addEventListener('popstate', onPopState)\n return () => window.removeEventListener('popstate', onPopState)\n }, [syncKey, readQuery, isSelectable, value])\n\n const tablistRef = useRef<HTMLDivElement | null>(null)\n const tabSelector = (v: string) =>\n `[data-value=\"${typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(v) : v}\"]`\n const focusTab = (v: string) => {\n tablistRef.current?.querySelector<HTMLElement>(tabSelector(v))?.focus()\n }\n\n // optionally move focus onto the active tab once, on mount (e.g. inside a popover that just opened)\n useEffect(() => {\n if (autoFocus && activeRef.current != null) focusTab(activeRef.current)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // keep the active tab in view when the strip overflows — by moving the tablist's OWN scroll offset\n // only. (scrollIntoView would also scroll every scrollable ancestor — i.e. the page — yanking a\n // below-the-fold strip's section into view on mount.)\n useEffect(() => {\n if (active == null) return\n const list = tablistRef.current\n const el = list?.querySelector<HTMLElement>(tabSelector(active))\n if (!list || !el) return\n const listRect = list.getBoundingClientRect()\n const elRect = el.getBoundingClientRect()\n if (orientation === 'vertical') {\n const top = elRect.top - listRect.top + list.scrollTop\n const bottom = top + elRect.height\n if (top < list.scrollTop) list.scrollTop = top\n else if (bottom > list.scrollTop + list.clientHeight)\n list.scrollTop = bottom - list.clientHeight\n } else {\n const left = elRect.left - listRect.left + list.scrollLeft\n const right = left + elRect.width\n if (left < list.scrollLeft) list.scrollLeft = left\n else if (right > list.scrollLeft + list.clientWidth)\n list.scrollLeft = right - list.clientWidth\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const enabled = items.filter((i) => !i.disabled)\n if (enabled.length === 0) return\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n const current = enabled.findIndex((i) => i.value === active)\n let target = -1\n switch (event.key) {\n case prevKey:\n target = (current - 1 + enabled.length) % enabled.length\n break\n case nextKey:\n target = (current + 1) % enabled.length\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = enabled.length - 1\n break\n default:\n return\n }\n event.preventDefault()\n const next = enabled[target].value\n select(next)\n focusTab(next)\n }\n\n const renderIcon = (icon: TabItem['icon']) =>\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n\n const activeItem = items.find((i) => i.value === active)\n const panelId = `${reactId}-panel`\n const tabId = (v: string) => `${reactId}-tab-${v}`\n\n return (\n <div ref={ref} className={clsx(styles.root, styles[orientation], className)} style={style}>\n <div\n ref={tablistRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={orientation}\n className={clsx(\n styles.tablist,\n styles[variant],\n styles[size],\n styles[orientation],\n fullWidth && orientation === 'horizontal' && styles.fullWidth,\n )}\n onKeyDown={handleKeyDown}\n >\n {items.map((item) => {\n const selected = item.value === active\n // the tab keeps its theme color; `error` shows up only as a red dot, not a full-tab tint\n const tint = color\n const icon = renderIcon(item.icon)\n const hasCount = item.badge != null && item.badge !== 0\n // a dot shows for an explicit `dot` (tinted) or an `error` tab (red — see CSS); count wins\n const showDot = !hasCount && (item.dot || item.error)\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n data-value={item.value}\n id={tabId(item.value)}\n aria-selected={selected}\n aria-label={item.label == null ? (item.ariaLabel ?? item.value) : item.ariaLabel}\n aria-controls={selected && item.content != null ? panelId : undefined}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n tabIndex={selected ? 0 : -1}\n className={clsx(styles.tab, selected && styles.active, item.error && styles.error)}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${tint}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${tint}-contrast, #fff)`,\n } as CSSProperties\n }\n onClick={() => select(item.value)}\n >\n <span className={styles.inner}>\n {icon != null && <span className={styles.icon}>{icon}</span>}\n {item.label != null && <span className={styles.label}>{item.label}</span>}\n {hasCount && (\n <span className={styles.count}>\n {typeof item.badge === 'number' && item.badge > 99 ? '99+' : item.badge}\n </span>\n )}\n {showDot && <span className={styles.dot} aria-hidden=\"true\" />}\n </span>\n </button>\n )\n })}\n </div>\n\n {activeItem?.content != null && active != null && (\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={tabId(active)}\n tabIndex={0}\n className={styles.panel}\n >\n {/* a <Tabs> rendered in here is one level deeper → picks the nested query key by default */}\n <TabsDepthContext.Provider value={depth + 1}>\n {activeItem.content}\n </TabsDepthContext.Provider>\n </div>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","TabsDepthContext","createContext","Tabs","forwardRef","items","value","defaultValue","onChange","queryKey","pushHistory","variant","size","color","orientation","fullWidth","autoFocus","className","style","ariaLabel","ref","reactId","useId","depth","useContext","tabQueryKey","useTabsQueryKey","nestedTabQueryKey","useNestedTabQueryKey","syncKey","isSelectable","useCallback","v","i","readQuery","firstEnabled","_a","internal","setInternal","useState","q","isControlled","raw","active","activeRef","useRef","onChangeRef","pushIntent","writeQuery","next","push","params","url","select","useEffect","onPopState","tablistRef","tabSelector","focusTab","_b","list","el","listRect","elRect","top","bottom","left","right","handleKeyDown","event","enabled","prevKey","nextKey","current","target","renderIcon","icon","jsx","Icon","activeItem","panelId","tabId","jsxs","clsx","styles","item","selected","tint","hasCount","showDot"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Tabs-DJMfAUni.js","sources":["../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useNestedTabQueryKey, useTabsQueryKey, type ThemeColor } from '../../theme'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { Icon } from '../Icon'\nimport styles from './Tabs.module.css'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/**\n * Tracks `<Tabs>` nesting depth via context: a top-level strip is depth `0`, a strip rendered inside\n * another tab's panel is `1`, and so on. Used to pick the right default URL query key (`tabQueryKey` at\n * depth `0`, else `nestedTabQueryKey`) so nested strips don't collide on the same param. Default `0`.\n */\nconst TabsDepthContext = createContext(0)\n\nexport type TabsVariant = 'underline' | 'pill'\nexport type TabsSize = 'sm' | 'md' | 'lg'\nexport type TabsOrientation = 'horizontal' | 'vertical'\n\nexport interface TabItem {\n /** Unique value — also what's written to the URL query and passed to `onChange`. */\n value: string\n /** Tab label. */\n label?: ReactNode\n /** Accessible name — required for an icon-only tab (no visible `label`); falls back to `value`. */\n ariaLabel?: string\n /** Leading icon — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Disables the tab (not selectable; skipped by keyboard nav). */\n disabled?: boolean\n /** Marks the tab invalid — shows a small **red** dot (e.g. its section failed validation). No full-tab tint. */\n error?: boolean\n /** Small dot indicator in the tab color (e.g. unread / notification). `error` shows a red one instead. */\n dot?: boolean\n /** Count / text indicator (rendered with `Badge`); wins over `dot`. */\n badge?: number | string\n /** Panel content rendered below (or beside) the strip while this tab is active. Optional. */\n content?: ReactNode\n}\n\nexport interface TabsProps {\n /** The tabs. */\n items: TabItem[]\n /** Controlled active value. */\n value?: string\n /**\n * Initial active value (uncontrolled). Falls back to the URL query (when URL sync is active and the\n * param is present) and otherwise the first enabled tab.\n */\n defaultValue?: string\n /** Fires with the next active value. */\n onChange?: (value: string) => void\n /**\n * URL query param name to sync the active tab to (e.g. `'tab'` → `?tab=general`), so a page refresh\n * restores it. **Defaults to the configured `keys.tabQueryKey` (else `'tab'`)** at the top level, and\n * `keys.nestedTabQueryKey` (else `'nestedTab'`) for a strip **nested** inside another tab's panel — so\n * the two don't collide (auto-applied by nesting depth). Every tab strip URL-syncs out of the box.\n * Pass **`null`** to opt out (state only). For 3+ nesting levels, set distinct keys explicitly.\n */\n queryKey?: string | null\n /**\n * Push a history entry on each tab change, so the browser **Back** button returns to the previous\n * tab. Defaults to `false` — tab changes **replace** the URL, so Back leaves the page instead of\n * stepping through tabs (and `popstate` still restores a tab when one is in the query).\n */\n pushHistory?: boolean\n /** Visual style. Defaults to `'underline'`. */\n variant?: TabsVariant\n /** Preset size. Defaults to `'md'`. */\n size?: TabsSize\n /** Theme palette token tinting the active tab. Defaults to `'primary'`. */\n color?: ThemeColor\n /** Strip direction. Defaults to `'horizontal'`. */\n orientation?: TabsOrientation\n /** Stretch the tabs to fill the strip equally (horizontal only). */\n fullWidth?: boolean\n /** Focus the active tab on mount (e.g. when the strip lives inside a popover that just opened). */\n autoFocus?: boolean\n /** Accessible label for the tablist. */\n 'aria-label'?: string\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A tab strip with optional panels. Data-driven via `items` (each: `label`, `icon`, `disabled`,\n * `error`, `dot`/`badge` via `Badge`, optional `content`). Controlled (`value` + `onChange`) or\n * uncontrolled (`defaultValue`). The active tab **syncs to the URL query by default** under\n * **`queryKey`** (defaults to the configured `keys.tabQueryKey`, else `'tab'` — and `keys.nestedTabQueryKey`,\n * else `'nestedTab'`, for a strip nested in another tab's panel: `?<queryKey>=<value>`) so a\n * refresh restores it — pass **`queryKey={null}`** to opt out. Tab changes **replace** the URL by\n * default (so Back doesn't step through tabs); pass **`pushHistory`** to make Back navigate tabs. Full\n * keyboard support (Arrows / Home / End, roving tabindex) and `role=\"tablist\"`/`tab`/`tabpanel` a11y.\n */\nexport const Tabs = forwardRef<HTMLDivElement, TabsProps>(function Tabs(\n {\n items,\n value,\n defaultValue,\n onChange,\n queryKey,\n pushHistory = false,\n variant = 'underline',\n size = 'md',\n color = 'primary',\n orientation = 'horizontal',\n fullWidth = false,\n autoFocus = false,\n className,\n style,\n 'aria-label': ariaLabel,\n },\n ref,\n) {\n const reactId = useId()\n\n // resolve the URL-sync key: an explicit `null` opts out (state only); omitting it falls back to the\n // configured default — `keys.tabQueryKey` for a top-level strip, `keys.nestedTabQueryKey` for one\n // nested inside another tab's panel (by depth) — so nested strips don't collide on the same param.\n const depth = useContext(TabsDepthContext)\n const tabQueryKey = useTabsQueryKey()\n const nestedTabQueryKey = useNestedTabQueryKey()\n const configQueryKey = depth === 0 ? tabQueryKey : nestedTabQueryKey\n const syncKey = queryKey === null ? undefined : (queryKey ?? configQueryKey)\n\n const isSelectable = useCallback(\n (v: string | null | undefined): v is string =>\n !!v && items.some((i) => i.value === v && !i.disabled),\n [items],\n )\n\n const readQuery = useCallback((): string | null => {\n if (!syncKey || typeof window === 'undefined') return null\n return new URLSearchParams(window.location.search).get(syncKey)\n }, [syncKey])\n\n // undefined when every tab is disabled — better than defaulting to a disabled tab (nothing active)\n const firstEnabled = items.find((i) => !i.disabled)?.value\n\n const [internal, setInternal] = useState<string | undefined>(() => {\n const q = readQuery()\n if (isSelectable(q)) return q\n return isSelectable(defaultValue) ? defaultValue : firstEnabled\n })\n const isControlled = value !== undefined\n const raw = isControlled ? value : internal\n // clamp to a present, enabled tab — guarantees a focusable roving tabstop + a rendered panel (no\n // keyboard trap) and keeps a bogus/disabled value out of the URL; falls back to the first enabled tab\n const active = isSelectable(raw) ? raw : firstEnabled\n\n // keep the latest active / onChange / push-intent for the stable effects + popstate listener\n const activeRef = useRef(active)\n activeRef.current = active\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const pushIntent = useRef(false)\n\n const writeQuery = useCallback(\n (next: string, push: boolean) => {\n if (!syncKey || typeof window === 'undefined') return\n const params = new URLSearchParams(window.location.search)\n if (params.get(syncKey) === next) return\n params.set(syncKey, next)\n const url = `${window.location.pathname}?${params.toString()}${window.location.hash}`\n window.history[push ? 'pushState' : 'replaceState'](window.history.state, '', url)\n },\n [syncKey],\n )\n\n const select = (next: string) => {\n if (next === activeRef.current) return\n pushIntent.current = true\n if (!isControlled) setInternal(next)\n onChange?.(next)\n }\n\n // mirror the *resolved* active tab into the URL whenever it changes (and on mount = canonicalize), so\n // the URL never holds a bogus value and a controlled value-change still syncs. A user-driven change\n // `push`es when `pushHistory` (Back walks tabs); programmatic / popstate changes just `replace`.\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined' || active == null) return\n const push = pushIntent.current && pushHistory\n pushIntent.current = false\n writeQuery(active, push)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [syncKey, active, pushHistory, writeQuery])\n\n // Back/Forward → restore the tab from the query\n useEffect(() => {\n if (!syncKey || typeof window === 'undefined') return\n const onPopState = () => {\n const q = readQuery()\n if (isSelectable(q) && q !== activeRef.current) {\n if (value === undefined) setInternal(q)\n onChangeRef.current?.(q)\n }\n }\n window.addEventListener('popstate', onPopState)\n return () => window.removeEventListener('popstate', onPopState)\n }, [syncKey, readQuery, isSelectable, value])\n\n const tablistRef = useRef<HTMLDivElement | null>(null)\n const tabSelector = (v: string) =>\n `[data-value=\"${typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(v) : v}\"]`\n const focusTab = (v: string) => {\n tablistRef.current?.querySelector<HTMLElement>(tabSelector(v))?.focus()\n }\n\n // optionally move focus onto the active tab once, on mount (e.g. inside a popover that just opened)\n useEffect(() => {\n if (autoFocus && activeRef.current != null) focusTab(activeRef.current)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // keep the active tab in view when the strip overflows — by moving the tablist's OWN scroll offset\n // only. (scrollIntoView would also scroll every scrollable ancestor — i.e. the page — yanking a\n // below-the-fold strip's section into view on mount.)\n useEffect(() => {\n if (active == null) return\n const list = tablistRef.current\n const el = list?.querySelector<HTMLElement>(tabSelector(active))\n if (!list || !el) return\n const listRect = list.getBoundingClientRect()\n const elRect = el.getBoundingClientRect()\n if (orientation === 'vertical') {\n const top = elRect.top - listRect.top + list.scrollTop\n const bottom = top + elRect.height\n if (top < list.scrollTop) list.scrollTop = top\n else if (bottom > list.scrollTop + list.clientHeight)\n list.scrollTop = bottom - list.clientHeight\n } else {\n const left = elRect.left - listRect.left + list.scrollLeft\n const right = left + elRect.width\n if (left < list.scrollLeft) list.scrollLeft = left\n else if (right > list.scrollLeft + list.clientWidth)\n list.scrollLeft = right - list.clientWidth\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const enabled = items.filter((i) => !i.disabled)\n if (enabled.length === 0) return\n const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n const current = enabled.findIndex((i) => i.value === active)\n let target = -1\n switch (event.key) {\n case prevKey:\n target = (current - 1 + enabled.length) % enabled.length\n break\n case nextKey:\n target = (current + 1) % enabled.length\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = enabled.length - 1\n break\n default:\n return\n }\n event.preventDefault()\n const next = enabled[target].value\n select(next)\n focusTab(next)\n }\n\n const renderIcon = (icon: TabItem['icon']) =>\n typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} size={size} />\n ) : (\n icon\n )\n\n const activeItem = items.find((i) => i.value === active)\n const panelId = `${reactId}-panel`\n const tabId = (v: string) => `${reactId}-tab-${v}`\n\n return (\n <div ref={ref} className={clsx(styles.root, styles[orientation], className)} style={style}>\n <div\n ref={tablistRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={orientation}\n className={clsx(\n styles.tablist,\n styles[variant],\n styles[size],\n styles[orientation],\n fullWidth && orientation === 'horizontal' && styles.fullWidth,\n )}\n onKeyDown={handleKeyDown}\n >\n {items.map((item) => {\n const selected = item.value === active\n // the tab keeps its theme color; `error` shows up only as a red dot, not a full-tab tint\n const tint = color\n const icon = renderIcon(item.icon)\n const hasCount = item.badge != null && item.badge !== 0\n // a dot shows for an explicit `dot` (tinted) or an `error` tab (red — see CSS); count wins\n const showDot = !hasCount && (item.dot || item.error)\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n data-value={item.value}\n id={tabId(item.value)}\n aria-selected={selected}\n aria-label={item.label == null ? (item.ariaLabel ?? item.value) : item.ariaLabel}\n aria-controls={selected && item.content != null ? panelId : undefined}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n tabIndex={selected ? 0 : -1}\n className={clsx(styles.tab, selected && styles.active, item.error && styles.error)}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${tint}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${tint}-contrast, #fff)`,\n } as CSSProperties\n }\n onClick={() => select(item.value)}\n >\n <span className={styles.inner}>\n {icon != null && <span className={styles.icon}>{icon}</span>}\n {item.label != null && <span className={styles.label}>{item.label}</span>}\n {hasCount && (\n <span className={styles.count}>\n {typeof item.badge === 'number' && item.badge > 99 ? '99+' : item.badge}\n </span>\n )}\n {showDot && <span className={styles.dot} aria-hidden=\"true\" />}\n </span>\n </button>\n )\n })}\n </div>\n\n {activeItem?.content != null && active != null && (\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={tabId(active)}\n tabIndex={0}\n className={styles.panel}\n >\n {/* a <Tabs> rendered in here is one level deeper → picks the nested query key by default */}\n <TabsDepthContext.Provider value={depth + 1}>\n {activeItem.content}\n </TabsDepthContext.Provider>\n </div>\n )}\n </div>\n )\n})\n"],"names":["ICON_NAME_SET","ICON_NAMES","TabsDepthContext","createContext","Tabs","forwardRef","items","value","defaultValue","onChange","queryKey","pushHistory","variant","size","color","orientation","fullWidth","autoFocus","className","style","ariaLabel","ref","reactId","useId","depth","useContext","tabQueryKey","useTabsQueryKey","nestedTabQueryKey","useNestedTabQueryKey","syncKey","isSelectable","useCallback","v","i","readQuery","firstEnabled","_a","internal","setInternal","useState","q","isControlled","raw","active","activeRef","useRef","onChangeRef","pushIntent","writeQuery","next","push","params","url","select","useEffect","onPopState","tablistRef","tabSelector","focusTab","_b","list","el","listRect","elRect","top","bottom","left","right","handleKeyDown","event","enabled","prevKey","nextKey","current","target","renderIcon","icon","jsx","Icon","activeItem","panelId","tabId","jsxs","clsx","styles","item","selected","tint","hasCount","showDot"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const r=require("react/jsx-runtime"),u=require("react"),M=require("clsx"),at=require("./formContext-bTWrqdEV.cjs"),dt=require("./Chip-
|
|
2
|
-
//# sourceMappingURL=TagsField-
|
|
1
|
+
"use strict";const r=require("react/jsx-runtime"),u=require("react"),M=require("clsx"),at=require("./formContext-bTWrqdEV.cjs"),dt=require("./Chip-CdKUtUGE.cjs"),ut=require("./Icon-BVULqOJD.cjs"),mt=require("./IconButton-Lv0sDDR9.cjs"),V=require("./Typography-BFatE1_A.cjs"),ft=require("./ConfigProvider-C7DUWHrb.cjs"),_t="_field_10m23_1",pt="_fullWidth_10m23_7",ht="_label_10m23_13",gt="_required_10m23_20",xt="_control_10m23_26",yt="_tags_10m23_45",jt="_tagsFilled_10m23_60",qt="_input_10m23_65",vt="_addButton_10m23_94",Ft="_sm_10m23_102",Tt="_md_10m23_107",bt="_lg_10m23_112",Bt="_error_10m23_118",It="_disabled_10m23_128",Nt="_helper_10m23_138",s={field:_t,fullWidth:pt,label:ht,required:gt,control:xt,tags:yt,tagsFilled:jt,input:qt,addButton:vt,sm:Ft,md:Tt,lg:bt,error:Bt,disabled:It,helper:Nt};function C(a,m){return(Array.isArray(a)?a:typeof a=="string"?m?a.split(m):[a]:[]).map(q=>q.trim()).filter(Boolean)}const kt=u.forwardRef(function({label:m,size:g="md",error:q,helperText:H,required:L=!1,fullWidth:G=!0,disabled:x=!1,value:v,defaultValue:S,onChange:F,separator:n=",",color:J="primary",allowDuplicates:O=!1,placeholder:Q,addIcon:U,addLabel:X,name:f,id:Y,className:Z,style:P,onKeyDown:d,onBlur:T,onPaste:b,...z},_){const w=u.useId(),B=Y??w,R=`${B}-helper`,y=at.useFormContext(),p=!!(y&&f),i=p?y.field(f):void 0,K=p?y.values[f]:void 0,I=q??(i==null?void 0:i.error)??!1,N=H??(i==null?void 0:i.helperText),k=v!==void 0?v:p?K:void 0,E=v!==void 0||p,tt=ft.useT(),et=typeof(k!==void 0?k:S)=="string",[st,lt]=u.useState(()=>C(S,n)),o=E?C(k,n):st,[l,W]=u.useState(""),$=u.useRef(null),rt=u.useCallback(t=>{$.current=t,typeof _=="function"?_(t):_&&(_.current=t)},[_]),A=t=>{E||lt(t);const e=et?t.join(n):t;p&&y.setValue(f,e),F==null||F(e)},h=t=>{const e=C(t,n);if(W(""),!e.length)return;const c=[...o];for(const j of e)!O&&c.includes(j)||c.push(j);c.length!==o.length&&A(c)},D=t=>{A(o.filter((e,c)=>c!==t))},it=t=>{if(t.nativeEvent.isComposing){d==null||d(t);return}t.key==="Enter"||n.length===1&&t.key===n?(t.preventDefault(),h(l)):t.key==="Backspace"&&l===""&&o.length>0&&(t.preventDefault(),D(o.length-1)),d==null||d(t)},ct=t=>{l.trim()&&h(l),i==null||i.onBlur(t),T==null||T(t)},nt=t=>{const e=t.clipboardData.getData("text");if(e&&n&&e.includes(n)){t.preventDefault();const c=t.currentTarget,j=c.selectionStart??l.length,ot=c.selectionEnd??l.length;h(l.slice(0,j)+e+l.slice(ot))}b==null||b(t)};return r.jsxs("div",{className:M.clsx(s.field,s[g],G&&s.fullWidth,I&&s.error,x&&s.disabled,Z),style:P,children:[m!=null&&r.jsxs("label",{htmlFor:B,className:s.label,children:[r.jsx(V.Typography,{as:"span",variant:"bodySmall",color:"muted",children:m}),L&&r.jsx("span",{className:s.required,"aria-hidden":"true",children:"*"})]}),r.jsxs("div",{className:s.control,children:[r.jsxs("div",{className:M.clsx(s.tags,o.length>0&&s.tagsFilled),onClick:()=>{var t;return(t=$.current)==null?void 0:t.focus()},children:[o.map((t,e)=>r.jsx(dt.Chip,{size:g,color:J,disabled:x,onDelete:()=>D(e),deleteLabel:`Remove ${t}`,children:t},`${t}-${e}`)),r.jsx("input",{ref:rt,id:B,name:f,className:s.input,value:l,placeholder:o.length===0?Q:void 0,disabled:x,"aria-invalid":I||void 0,"aria-describedby":N!=null?R:void 0,onChange:t=>W(t.target.value),onKeyDown:it,onBlur:ct,onPaste:nt,...z})]}),r.jsx(mt.IconButton,{type:"button",variant:"text",color:"primary",size:g,disabled:x||l.trim()==="","aria-label":X??tt("tagsField.add"),className:s.addButton,onMouseDown:t=>t.preventDefault(),onClick:()=>h(l),children:U??r.jsx(ut.Icon,{name:"Add"})})]}),N!=null&&r.jsx(V.Typography,{as:"span",id:R,variant:"bodySmall",color:I?"error":"muted",className:s.helper,children:N})]})});exports.TagsField=kt;
|
|
2
|
+
//# sourceMappingURL=TagsField-4x3RmGwt.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagsField-BIxwLfSJ.cjs","sources":["../src/components/TagsField/TagsField.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useId,\n useRef,\n useState,\n type ClipboardEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useFormContext } from '../../form/formContext'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Chip } from '../Chip'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Typography } from '../Typography'\nimport styles from './TagsField.module.css'\n\nexport type TagsFieldSize = 'sm' | 'md' | 'lg'\n\n/** Splits a value (array or `separator`-joined string) into trimmed, non-empty tags. */\nfunction toTags(value: string[] | string | undefined, separator: string): string[] {\n const parts = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? separator\n ? value.split(separator)\n : [value] // empty separator → don't explode into per-character tags\n : []\n return parts.map((t) => t.trim()).filter(Boolean)\n}\n\nexport interface TagsFieldProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'color' | 'value' | 'defaultValue' | 'onChange'\n> {\n /** Label rendered above the field. */\n label?: ReactNode\n /** Preset size — control height, font and chips. */\n size?: TagsFieldSize\n /** Marks the field invalid: red border/focus ring and the `helperText` shown in the error color. */\n error?: boolean\n /** Helper / validation text under the field. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the field to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /** Disables the field (no typing, no add/remove). */\n disabled?: boolean\n /** Controlled value — a `string[]` or a `separator`-joined `string` (e.g. `\"react;typescript\"`). */\n value?: string[] | string\n /** Initial value for uncontrolled use (`string[]` or a joined `string`). */\n defaultValue?: string[] | string\n /** Fires with the next tags, mirroring the input shape: a `string[]`, or a joined `string` when the value is a string. */\n onChange?: (value: string[] | string) => void\n /** Character/string that splits typed & pasted input and joins the value when it's a string. Defaults to `,`. */\n separator?: string\n /** Theme palette token tinting the tag chips. Defaults to `primary`. */\n color?: ThemeColor\n /** Allow the same tag more than once. Off by default (duplicates are ignored). */\n allowDuplicates?: boolean\n /** Placeholder shown in the input while there are no tags. */\n placeholder?: string\n /** Icon for the add button. Defaults to an `Add` icon. */\n addIcon?: ReactNode\n /** Accessible label for the add button. Defaults to `\"Add tag\"`. */\n addLabel?: string\n}\n\n/**\n * A tags / token input. Type a value and press **Enter**, the **add button**, or the `separator`\n * key to commit it as a tag; remove a tag via its chip's delete button (or Backspace on the empty\n * input). The **`separator`** (default `,`) also splits pasted text, so pasting `\"react;typescript\"`\n * (with `separator=\";\"`) adds both at once. The value accepts — and `onChange` mirrors — **either a\n * `string[]` or a `separator`-joined `string`**, so it binds to a `<Form>` schema of either shape.\n * Shares TextField's chrome (label, helper/error, sizes, `<Form>` binding by `name` for validation).\n * Controlled (`value` + `onChange`) or uncontrolled (`defaultValue`). Token-only styling.\n */\nexport const TagsField = forwardRef<HTMLInputElement, TagsFieldProps>(function TagsField(\n {\n label,\n size = 'md',\n error,\n helperText,\n required = false,\n fullWidth = true,\n disabled = false,\n value,\n defaultValue,\n onChange,\n separator = ',',\n color = 'primary',\n allowDuplicates = false,\n placeholder,\n addIcon,\n addLabel,\n name,\n id: idProp,\n className,\n style,\n onKeyDown,\n onBlur,\n onPaste,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n // Auto-bind to a surrounding <Form> by `name`. error/helper/onBlur come from field(), but the VALUE\n // is read RAW from `form.values` — field().value is always String-coerced, which would flatten a\n // `string[]` into a joined string and break an array schema. Same pattern as NumberField/ColorPicker.\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = isFormBound ? form!.field(name!) : undefined\n const rawFormValue = isFormBound\n ? (form!.values[name!] as string[] | string | undefined)\n : undefined\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n\n const externalValue = value !== undefined ? value : isFormBound ? rawFormValue : undefined\n const isControlled = value !== undefined || isFormBound\n // Mirror the value's shape on output: a joined string when the source is a string, else an array.\n const t = useT()\n const shapeSource = externalValue !== undefined ? externalValue : defaultValue\n const stringMode = typeof shapeSource === 'string'\n\n const [internal, setInternal] = useState<string[]>(() => toTags(defaultValue, separator))\n const tags = isControlled ? toTags(externalValue, separator) : internal\n\n const [input, setInput] = useState('')\n\n const inputRef = useRef<HTMLInputElement | null>(null)\n const setRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: HTMLInputElement | null }).current = node\n },\n [ref],\n )\n\n const commit = (nextTags: string[]) => {\n if (!isControlled) setInternal(nextTags)\n const out: string[] | string = stringMode ? nextTags.join(separator) : nextTags\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n const addTags = (raw: string) => {\n const parts = toTags(raw, separator)\n setInput('')\n if (!parts.length) return\n const next = [...tags]\n for (const part of parts) {\n if (!allowDuplicates && next.includes(part)) continue\n next.push(part)\n }\n if (next.length !== tags.length) commit(next)\n }\n\n const removeTag = (index: number) => {\n commit(tags.filter((_, i) => i !== index))\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // while an IME is composing (CJK etc.), Enter/separator confirm the candidate — not a commit\n if (event.nativeEvent.isComposing) {\n onKeyDown?.(event)\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n addTags(input)\n } else if (separator.length === 1 && event.key === separator) {\n event.preventDefault()\n addTags(input)\n } else if (event.key === 'Backspace' && input === '' && tags.length > 0) {\n event.preventDefault()\n removeTag(tags.length - 1)\n }\n onKeyDown?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n if (input.trim()) addTags(input) // don't lose a typed-but-not-committed tag\n bound?.onBlur(event)\n onBlur?.(event)\n }\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {\n const text = event.clipboardData.getData('text')\n if (text && separator && text.includes(separator)) {\n event.preventDefault()\n // splice the pasted, separator-delimited text into the input at the caret/selection\n const el = event.currentTarget\n const start = el.selectionStart ?? input.length\n const end = el.selectionEnd ?? input.length\n addTags(input.slice(0, start) + text + input.slice(end))\n }\n onPaste?.(event)\n }\n\n return (\n <div\n className={clsx(\n styles.field,\n styles[size],\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style as CSSProperties}\n >\n {label != null && (\n <label htmlFor={id} className={styles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={styles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div className={styles.control}>\n {/* clicking anywhere in the tag area focuses the input */}\n <div\n className={clsx(styles.tags, tags.length > 0 && styles.tagsFilled)}\n onClick={() => inputRef.current?.focus()}\n >\n {tags.map((tag, index) => (\n <Chip\n key={`${tag}-${index}`}\n size={size}\n color={color}\n disabled={disabled}\n onDelete={() => removeTag(index)}\n deleteLabel={`Remove ${tag}`}\n >\n {tag}\n </Chip>\n ))}\n <input\n ref={setRef}\n id={id}\n name={name}\n className={styles.input}\n value={input}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n aria-invalid={resolvedError || undefined}\n aria-describedby={resolvedHelperText != null ? helperId : undefined}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onPaste={handlePaste}\n {...props}\n />\n </div>\n <IconButton\n type=\"button\"\n variant=\"text\"\n color=\"primary\"\n size={size}\n disabled={disabled || input.trim() === ''}\n aria-label={addLabel ?? t('tagsField.add')}\n className={styles.addButton}\n // keep the input's focus ring while clicking add (don't steal focus → blur → double add)\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => addTags(input)}\n >\n {addIcon ?? <Icon name=\"Add\" />}\n </IconButton>\n </div>\n\n {resolvedHelperText != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={resolvedError ? 'error' : 'muted'}\n className={styles.helper}\n >\n {resolvedHelperText}\n </Typography>\n )}\n </div>\n )\n})\n"],"names":["toTags","value","separator","t","TagsField","forwardRef","label","size","error","helperText","required","fullWidth","disabled","defaultValue","onChange","color","allowDuplicates","placeholder","addIcon","addLabel","name","idProp","className","style","onKeyDown","onBlur","onPaste","props","ref","reactId","useId","id","helperId","form","useFormContext","isFormBound","bound","rawFormValue","resolvedError","resolvedHelperText","externalValue","isControlled","useT","stringMode","internal","setInternal","useState","tags","input","setInput","inputRef","useRef","setRef","useCallback","node","commit","nextTags","out","addTags","raw","parts","next","part","removeTag","index","_","i","handleKeyDown","event","handleBlur","handlePaste","text","el","start","end","jsxs","clsx","styles","jsx","Typography","_a","tag","Chip","IconButton","Icon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TagsField-4x3RmGwt.cjs","sources":["../src/components/TagsField/TagsField.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useId,\n useRef,\n useState,\n type ClipboardEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useFormContext } from '../../form/formContext'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Chip } from '../Chip'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Typography } from '../Typography'\nimport styles from './TagsField.module.css'\n\nexport type TagsFieldSize = 'sm' | 'md' | 'lg'\n\n/** Splits a value (array or `separator`-joined string) into trimmed, non-empty tags. */\nfunction toTags(value: string[] | string | undefined, separator: string): string[] {\n const parts = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? separator\n ? value.split(separator)\n : [value] // empty separator → don't explode into per-character tags\n : []\n return parts.map((t) => t.trim()).filter(Boolean)\n}\n\nexport interface TagsFieldProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'color' | 'value' | 'defaultValue' | 'onChange'\n> {\n /** Label rendered above the field. */\n label?: ReactNode\n /** Preset size — control height, font and chips. */\n size?: TagsFieldSize\n /** Marks the field invalid: red border/focus ring and the `helperText` shown in the error color. */\n error?: boolean\n /** Helper / validation text under the field. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the field to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /** Disables the field (no typing, no add/remove). */\n disabled?: boolean\n /** Controlled value — a `string[]` or a `separator`-joined `string` (e.g. `\"react;typescript\"`). */\n value?: string[] | string\n /** Initial value for uncontrolled use (`string[]` or a joined `string`). */\n defaultValue?: string[] | string\n /** Fires with the next tags, mirroring the input shape: a `string[]`, or a joined `string` when the value is a string. */\n onChange?: (value: string[] | string) => void\n /** Character/string that splits typed & pasted input and joins the value when it's a string. Defaults to `,`. */\n separator?: string\n /** Theme palette token tinting the tag chips. Defaults to `primary`. */\n color?: ThemeColor\n /** Allow the same tag more than once. Off by default (duplicates are ignored). */\n allowDuplicates?: boolean\n /** Placeholder shown in the input while there are no tags. */\n placeholder?: string\n /** Icon for the add button. Defaults to an `Add` icon. */\n addIcon?: ReactNode\n /** Accessible label for the add button. Defaults to `\"Add tag\"`. */\n addLabel?: string\n}\n\n/**\n * A tags / token input. Type a value and press **Enter**, the **add button**, or the `separator`\n * key to commit it as a tag; remove a tag via its chip's delete button (or Backspace on the empty\n * input). The **`separator`** (default `,`) also splits pasted text, so pasting `\"react;typescript\"`\n * (with `separator=\";\"`) adds both at once. The value accepts — and `onChange` mirrors — **either a\n * `string[]` or a `separator`-joined `string`**, so it binds to a `<Form>` schema of either shape.\n * Shares TextField's chrome (label, helper/error, sizes, `<Form>` binding by `name` for validation).\n * Controlled (`value` + `onChange`) or uncontrolled (`defaultValue`). Token-only styling.\n */\nexport const TagsField = forwardRef<HTMLInputElement, TagsFieldProps>(function TagsField(\n {\n label,\n size = 'md',\n error,\n helperText,\n required = false,\n fullWidth = true,\n disabled = false,\n value,\n defaultValue,\n onChange,\n separator = ',',\n color = 'primary',\n allowDuplicates = false,\n placeholder,\n addIcon,\n addLabel,\n name,\n id: idProp,\n className,\n style,\n onKeyDown,\n onBlur,\n onPaste,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n // Auto-bind to a surrounding <Form> by `name`. error/helper/onBlur come from field(), but the VALUE\n // is read RAW from `form.values` — field().value is always String-coerced, which would flatten a\n // `string[]` into a joined string and break an array schema. Same pattern as NumberField/ColorPicker.\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = isFormBound ? form!.field(name!) : undefined\n const rawFormValue = isFormBound\n ? (form!.values[name!] as string[] | string | undefined)\n : undefined\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n\n const externalValue = value !== undefined ? value : isFormBound ? rawFormValue : undefined\n const isControlled = value !== undefined || isFormBound\n // Mirror the value's shape on output: a joined string when the source is a string, else an array.\n const t = useT()\n const shapeSource = externalValue !== undefined ? externalValue : defaultValue\n const stringMode = typeof shapeSource === 'string'\n\n const [internal, setInternal] = useState<string[]>(() => toTags(defaultValue, separator))\n const tags = isControlled ? toTags(externalValue, separator) : internal\n\n const [input, setInput] = useState('')\n\n const inputRef = useRef<HTMLInputElement | null>(null)\n const setRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: HTMLInputElement | null }).current = node\n },\n [ref],\n )\n\n const commit = (nextTags: string[]) => {\n if (!isControlled) setInternal(nextTags)\n const out: string[] | string = stringMode ? nextTags.join(separator) : nextTags\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n const addTags = (raw: string) => {\n const parts = toTags(raw, separator)\n setInput('')\n if (!parts.length) return\n const next = [...tags]\n for (const part of parts) {\n if (!allowDuplicates && next.includes(part)) continue\n next.push(part)\n }\n if (next.length !== tags.length) commit(next)\n }\n\n const removeTag = (index: number) => {\n commit(tags.filter((_, i) => i !== index))\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // while an IME is composing (CJK etc.), Enter/separator confirm the candidate — not a commit\n if (event.nativeEvent.isComposing) {\n onKeyDown?.(event)\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n addTags(input)\n } else if (separator.length === 1 && event.key === separator) {\n event.preventDefault()\n addTags(input)\n } else if (event.key === 'Backspace' && input === '' && tags.length > 0) {\n event.preventDefault()\n removeTag(tags.length - 1)\n }\n onKeyDown?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n if (input.trim()) addTags(input) // don't lose a typed-but-not-committed tag\n bound?.onBlur(event)\n onBlur?.(event)\n }\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {\n const text = event.clipboardData.getData('text')\n if (text && separator && text.includes(separator)) {\n event.preventDefault()\n // splice the pasted, separator-delimited text into the input at the caret/selection\n const el = event.currentTarget\n const start = el.selectionStart ?? input.length\n const end = el.selectionEnd ?? input.length\n addTags(input.slice(0, start) + text + input.slice(end))\n }\n onPaste?.(event)\n }\n\n return (\n <div\n className={clsx(\n styles.field,\n styles[size],\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style as CSSProperties}\n >\n {label != null && (\n <label htmlFor={id} className={styles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={styles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div className={styles.control}>\n {/* clicking anywhere in the tag area focuses the input */}\n <div\n className={clsx(styles.tags, tags.length > 0 && styles.tagsFilled)}\n onClick={() => inputRef.current?.focus()}\n >\n {tags.map((tag, index) => (\n <Chip\n key={`${tag}-${index}`}\n size={size}\n color={color}\n disabled={disabled}\n onDelete={() => removeTag(index)}\n deleteLabel={`Remove ${tag}`}\n >\n {tag}\n </Chip>\n ))}\n <input\n ref={setRef}\n id={id}\n name={name}\n className={styles.input}\n value={input}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n aria-invalid={resolvedError || undefined}\n aria-describedby={resolvedHelperText != null ? helperId : undefined}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onPaste={handlePaste}\n {...props}\n />\n </div>\n <IconButton\n type=\"button\"\n variant=\"text\"\n color=\"primary\"\n size={size}\n disabled={disabled || input.trim() === ''}\n aria-label={addLabel ?? t('tagsField.add')}\n className={styles.addButton}\n // keep the input's focus ring while clicking add (don't steal focus → blur → double add)\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => addTags(input)}\n >\n {addIcon ?? <Icon name=\"Add\" />}\n </IconButton>\n </div>\n\n {resolvedHelperText != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={resolvedError ? 'error' : 'muted'}\n className={styles.helper}\n >\n {resolvedHelperText}\n </Typography>\n )}\n </div>\n )\n})\n"],"names":["toTags","value","separator","t","TagsField","forwardRef","label","size","error","helperText","required","fullWidth","disabled","defaultValue","onChange","color","allowDuplicates","placeholder","addIcon","addLabel","name","idProp","className","style","onKeyDown","onBlur","onPaste","props","ref","reactId","useId","id","helperId","form","useFormContext","isFormBound","bound","rawFormValue","resolvedError","resolvedHelperText","externalValue","isControlled","useT","stringMode","internal","setInternal","useState","tags","input","setInput","inputRef","useRef","setRef","useCallback","node","commit","nextTags","out","addTags","raw","parts","next","part","removeTag","index","_","i","handleKeyDown","event","handleBlur","handlePaste","text","el","start","end","jsxs","clsx","styles","jsx","Typography","_a","tag","Chip","IconButton","Icon"],"mappings":"iyBAyBA,SAASA,EAAOC,EAAsCC,EAA6B,CAQjF,OAPc,MAAM,QAAQD,CAAK,EAC7BA,EACA,OAAOA,GAAU,SACfC,EACED,EAAM,MAAMC,CAAS,EACrB,CAACD,CAAK,EACR,CAAA,GACO,IAAKE,GAAMA,EAAE,KAAA,CAAM,EAAE,OAAO,OAAO,CAClD,CAiDO,MAAMC,GAAYC,EAAAA,WAA6C,SACpE,CACE,MAAAC,EACA,KAAAC,EAAO,KACP,MAAAC,EACA,WAAAC,EACA,SAAAC,EAAW,GACX,UAAAC,EAAY,GACZ,SAAAC,EAAW,GACX,MAAAX,EACA,aAAAY,EACA,SAAAC,EACA,UAAAZ,EAAY,IACZ,MAAAa,EAAQ,UACR,gBAAAC,EAAkB,GAClB,YAAAC,EACA,QAAAC,EACA,SAAAC,EACA,KAAAC,EACA,GAAIC,EACJ,UAAAC,EACA,MAAAC,EACA,UAAAC,EACA,OAAAC,EACA,QAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,MAAMC,EAAUC,EAAAA,MAAA,EACVC,EAAKV,GAAUQ,EACfG,EAAW,GAAGD,CAAE,UAKhBE,EAAOC,GAAAA,eAAA,EACPC,EAAc,GAAQF,GAAQb,GAC9BgB,EAAQD,EAAcF,EAAM,MAAMb,CAAK,EAAI,OAC3CiB,EAAeF,EAChBF,EAAM,OAAOb,CAAK,EACnB,OAEEkB,EAAgB9B,IAAS4B,GAAA,YAAAA,EAAO,QAAS,GACzCG,EAAqB9B,IAAc2B,GAAA,YAAAA,EAAO,YAE1CI,EAAgBvC,IAAU,OAAYA,EAAQkC,EAAcE,EAAe,OAC3EI,EAAexC,IAAU,QAAakC,EAEtChC,GAAIuC,GAAAA,KAAA,EAEJC,GAAa,OADCH,IAAkB,OAAYA,EAAgB3B,IACxB,SAEpC,CAAC+B,GAAUC,EAAW,EAAIC,EAAAA,SAAmB,IAAM9C,EAAOa,EAAcX,CAAS,CAAC,EAClF6C,EAAON,EAAezC,EAAOwC,EAAetC,CAAS,EAAI0C,GAEzD,CAACI,EAAOC,CAAQ,EAAIH,EAAAA,SAAS,EAAE,EAE/BI,EAAWC,EAAAA,OAAgC,IAAI,EAC/CC,GAASC,EAAAA,YACZC,GAAkC,CACjCJ,EAAS,QAAUI,EACf,OAAO1B,GAAQ,WAAYA,EAAI0B,CAAI,EAC9B1B,IAAMA,EAA6C,QAAU0B,EACxE,EACA,CAAC1B,CAAG,CAAA,EAGA2B,EAAUC,GAAuB,CAChCf,GAAcI,GAAYW,CAAQ,EACvC,MAAMC,EAAyBd,GAAaa,EAAS,KAAKtD,CAAS,EAAIsD,EACnErB,GAAaF,EAAM,SAASb,EAAOqC,CAAG,EAC1C3C,GAAA,MAAAA,EAAW2C,EACb,EAEMC,EAAWC,GAAgB,CAC/B,MAAMC,EAAQ5D,EAAO2D,EAAKzD,CAAS,EAEnC,GADA+C,EAAS,EAAE,EACP,CAACW,EAAM,OAAQ,OACnB,MAAMC,EAAO,CAAC,GAAGd,CAAI,EACrB,UAAWe,KAAQF,EACb,CAAC5C,GAAmB6C,EAAK,SAASC,CAAI,GAC1CD,EAAK,KAAKC,CAAI,EAEZD,EAAK,SAAWd,EAAK,UAAec,CAAI,CAC9C,EAEME,EAAaC,GAAkB,CACnCT,EAAOR,EAAK,OAAO,CAACkB,EAAGC,IAAMA,IAAMF,CAAK,CAAC,CAC3C,EAEMG,GAAiBC,GAA2C,CAEhE,GAAIA,EAAM,YAAY,YAAa,CACjC5C,GAAA,MAAAA,EAAY4C,GACZ,MACF,CACIA,EAAM,MAAQ,SAGPlE,EAAU,SAAW,GAAKkE,EAAM,MAAQlE,GAFjDkE,EAAM,eAAA,EACNV,EAAQV,CAAK,GAIJoB,EAAM,MAAQ,aAAepB,IAAU,IAAMD,EAAK,OAAS,IACpEqB,EAAM,eAAA,EACNL,EAAUhB,EAAK,OAAS,CAAC,GAE3BvB,GAAA,MAAAA,EAAY4C,EACd,EAEMC,GAAcD,GAAwC,CACtDpB,EAAM,QAAQU,EAAQV,CAAK,EAC/BZ,GAAA,MAAAA,EAAO,OAAOgC,GACd3C,GAAA,MAAAA,EAAS2C,EACX,EAEME,GAAeF,GAA4C,CAC/D,MAAMG,EAAOH,EAAM,cAAc,QAAQ,MAAM,EAC/C,GAAIG,GAAQrE,GAAaqE,EAAK,SAASrE,CAAS,EAAG,CACjDkE,EAAM,eAAA,EAEN,MAAMI,EAAKJ,EAAM,cACXK,EAAQD,EAAG,gBAAkBxB,EAAM,OACnC0B,GAAMF,EAAG,cAAgBxB,EAAM,OACrCU,EAAQV,EAAM,MAAM,EAAGyB,CAAK,EAAIF,EAAOvB,EAAM,MAAM0B,EAAG,CAAC,CACzD,CACAhD,GAAA,MAAAA,EAAU0C,EACZ,EAEA,OACEO,EAAAA,KAAC,MAAA,CACC,UAAWC,EAAAA,KACTC,EAAO,MACPA,EAAOtE,CAAI,EACXI,GAAakE,EAAO,UACpBvC,GAAiBuC,EAAO,MACxBjE,GAAYiE,EAAO,SACnBvD,CAAA,EAEF,MAAAC,EAEC,SAAA,CAAAjB,GAAS,MACRqE,OAAC,QAAA,CAAM,QAAS5C,EAAI,UAAW8C,EAAO,MACpC,SAAA,CAAAC,EAAAA,IAACC,EAAAA,YAAW,GAAG,OAAO,QAAQ,YAAY,MAAM,QAC7C,SAAAzE,CAAA,CACH,EACCI,SACE,OAAA,CAAK,UAAWmE,EAAO,SAAU,cAAY,OAAO,SAAA,GAAA,CAErD,CAAA,EAEJ,EAGFF,EAAAA,KAAC,MAAA,CAAI,UAAWE,EAAO,QAErB,SAAA,CAAAF,EAAAA,KAAC,MAAA,CACC,UAAWC,EAAAA,KAAKC,EAAO,KAAM9B,EAAK,OAAS,GAAK8B,EAAO,UAAU,EACjE,QAAS,IAAA,OAAM,OAAAG,EAAA9B,EAAS,UAAT,YAAA8B,EAAkB,SAEhC,SAAA,CAAAjC,EAAK,IAAI,CAACkC,EAAKjB,IACdc,EAAAA,IAACI,GAAAA,KAAA,CAEC,KAAA3E,EACA,MAAAQ,EACA,SAAAH,EACA,SAAU,IAAMmD,EAAUC,CAAK,EAC/B,YAAa,UAAUiB,CAAG,GAEzB,SAAAA,CAAA,EAPI,GAAGA,CAAG,IAAIjB,CAAK,EAAA,CASvB,EACDc,EAAAA,IAAC,QAAA,CACC,IAAK1B,GACL,GAAArB,EACA,KAAAX,EACA,UAAWyD,EAAO,MAClB,MAAO7B,EACP,YAAaD,EAAK,SAAW,EAAI9B,EAAc,OAC/C,SAAAL,EACA,eAAc0B,GAAiB,OAC/B,mBAAkBC,GAAsB,KAAOP,EAAW,OAC1D,SAAWoC,GAAUnB,EAASmB,EAAM,OAAO,KAAK,EAChD,UAAWD,GACX,OAAQE,GACR,QAASC,GACR,GAAG3C,CAAA,CAAA,CACN,CAAA,CAAA,EAEFmD,EAAAA,IAACK,GAAAA,WAAA,CACC,KAAK,SACL,QAAQ,OACR,MAAM,UACN,KAAA5E,EACA,SAAUK,GAAYoC,EAAM,KAAA,IAAW,GACvC,aAAY7B,GAAYhB,GAAE,eAAe,EACzC,UAAW0E,EAAO,UAElB,YAAcT,GAAUA,EAAM,eAAA,EAC9B,QAAS,IAAMV,EAAQV,CAAK,EAE3B,SAAA9B,GAAW4D,EAAAA,IAACM,GAAAA,KAAA,CAAK,KAAK,KAAA,CAAM,CAAA,CAAA,CAC/B,EACF,EAEC7C,GAAsB,MACrBuC,EAAAA,IAACC,EAAAA,WAAA,CACC,GAAG,OACH,GAAI/C,EACJ,QAAQ,YACR,MAAOM,EAAgB,QAAU,QACjC,UAAWuC,EAAO,OAEjB,SAAAtC,CAAA,CAAA,CACH,CAAA,CAAA,CAIR,CAAC"}
|
|
@@ -2,11 +2,11 @@ import { jsxs as b, jsx as n } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as dt, useId as mt, useState as M, useRef as ut, useCallback as ft } from "react";
|
|
3
3
|
import { clsx as V } from "clsx";
|
|
4
4
|
import { u as pt } from "./formContext-B7ln1Miy.js";
|
|
5
|
-
import { C as _t } from "./Chip-
|
|
6
|
-
import { I as ht } from "./Icon-
|
|
7
|
-
import { I as gt } from "./IconButton-
|
|
5
|
+
import { C as _t } from "./Chip-BiqfnRUi.js";
|
|
6
|
+
import { I as ht } from "./Icon-DaTvzLBu.js";
|
|
7
|
+
import { I as gt } from "./IconButton-DXMmtuLA.js";
|
|
8
8
|
import { T as H } from "./Typography-Cta6Rg4L.js";
|
|
9
|
-
import { a as vt } from "./ConfigProvider-
|
|
9
|
+
import { a as vt } from "./ConfigProvider-DT0yrgmd.js";
|
|
10
10
|
const Ft = "_field_10m23_1", bt = "_fullWidth_10m23_7", yt = "_label_10m23_13", Tt = "_required_10m23_20", xt = "_control_10m23_26", It = "_tags_10m23_45", Bt = "_tagsFilled_10m23_60", Nt = "_input_10m23_65", kt = "_addButton_10m23_94", St = "_sm_10m23_102", Ct = "_md_10m23_107", Rt = "_lg_10m23_112", qt = "_error_10m23_118", Et = "_disabled_10m23_128", Wt = "_helper_10m23_138", l = {
|
|
11
11
|
field: Ft,
|
|
12
12
|
fullWidth: bt,
|
|
@@ -183,4 +183,4 @@ const Ot = dt(function({
|
|
|
183
183
|
export {
|
|
184
184
|
Ot as T
|
|
185
185
|
};
|
|
186
|
-
//# sourceMappingURL=TagsField-
|
|
186
|
+
//# sourceMappingURL=TagsField-Bvh6Fm5Y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagsField-CGFm17lP.js","sources":["../src/components/TagsField/TagsField.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useId,\n useRef,\n useState,\n type ClipboardEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useFormContext } from '../../form/formContext'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Chip } from '../Chip'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Typography } from '../Typography'\nimport styles from './TagsField.module.css'\n\nexport type TagsFieldSize = 'sm' | 'md' | 'lg'\n\n/** Splits a value (array or `separator`-joined string) into trimmed, non-empty tags. */\nfunction toTags(value: string[] | string | undefined, separator: string): string[] {\n const parts = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? separator\n ? value.split(separator)\n : [value] // empty separator → don't explode into per-character tags\n : []\n return parts.map((t) => t.trim()).filter(Boolean)\n}\n\nexport interface TagsFieldProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'color' | 'value' | 'defaultValue' | 'onChange'\n> {\n /** Label rendered above the field. */\n label?: ReactNode\n /** Preset size — control height, font and chips. */\n size?: TagsFieldSize\n /** Marks the field invalid: red border/focus ring and the `helperText` shown in the error color. */\n error?: boolean\n /** Helper / validation text under the field. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the field to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /** Disables the field (no typing, no add/remove). */\n disabled?: boolean\n /** Controlled value — a `string[]` or a `separator`-joined `string` (e.g. `\"react;typescript\"`). */\n value?: string[] | string\n /** Initial value for uncontrolled use (`string[]` or a joined `string`). */\n defaultValue?: string[] | string\n /** Fires with the next tags, mirroring the input shape: a `string[]`, or a joined `string` when the value is a string. */\n onChange?: (value: string[] | string) => void\n /** Character/string that splits typed & pasted input and joins the value when it's a string. Defaults to `,`. */\n separator?: string\n /** Theme palette token tinting the tag chips. Defaults to `primary`. */\n color?: ThemeColor\n /** Allow the same tag more than once. Off by default (duplicates are ignored). */\n allowDuplicates?: boolean\n /** Placeholder shown in the input while there are no tags. */\n placeholder?: string\n /** Icon for the add button. Defaults to an `Add` icon. */\n addIcon?: ReactNode\n /** Accessible label for the add button. Defaults to `\"Add tag\"`. */\n addLabel?: string\n}\n\n/**\n * A tags / token input. Type a value and press **Enter**, the **add button**, or the `separator`\n * key to commit it as a tag; remove a tag via its chip's delete button (or Backspace on the empty\n * input). The **`separator`** (default `,`) also splits pasted text, so pasting `\"react;typescript\"`\n * (with `separator=\";\"`) adds both at once. The value accepts — and `onChange` mirrors — **either a\n * `string[]` or a `separator`-joined `string`**, so it binds to a `<Form>` schema of either shape.\n * Shares TextField's chrome (label, helper/error, sizes, `<Form>` binding by `name` for validation).\n * Controlled (`value` + `onChange`) or uncontrolled (`defaultValue`). Token-only styling.\n */\nexport const TagsField = forwardRef<HTMLInputElement, TagsFieldProps>(function TagsField(\n {\n label,\n size = 'md',\n error,\n helperText,\n required = false,\n fullWidth = true,\n disabled = false,\n value,\n defaultValue,\n onChange,\n separator = ',',\n color = 'primary',\n allowDuplicates = false,\n placeholder,\n addIcon,\n addLabel,\n name,\n id: idProp,\n className,\n style,\n onKeyDown,\n onBlur,\n onPaste,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n // Auto-bind to a surrounding <Form> by `name`. error/helper/onBlur come from field(), but the VALUE\n // is read RAW from `form.values` — field().value is always String-coerced, which would flatten a\n // `string[]` into a joined string and break an array schema. Same pattern as NumberField/ColorPicker.\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = isFormBound ? form!.field(name!) : undefined\n const rawFormValue = isFormBound\n ? (form!.values[name!] as string[] | string | undefined)\n : undefined\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n\n const externalValue = value !== undefined ? value : isFormBound ? rawFormValue : undefined\n const isControlled = value !== undefined || isFormBound\n // Mirror the value's shape on output: a joined string when the source is a string, else an array.\n const t = useT()\n const shapeSource = externalValue !== undefined ? externalValue : defaultValue\n const stringMode = typeof shapeSource === 'string'\n\n const [internal, setInternal] = useState<string[]>(() => toTags(defaultValue, separator))\n const tags = isControlled ? toTags(externalValue, separator) : internal\n\n const [input, setInput] = useState('')\n\n const inputRef = useRef<HTMLInputElement | null>(null)\n const setRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: HTMLInputElement | null }).current = node\n },\n [ref],\n )\n\n const commit = (nextTags: string[]) => {\n if (!isControlled) setInternal(nextTags)\n const out: string[] | string = stringMode ? nextTags.join(separator) : nextTags\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n const addTags = (raw: string) => {\n const parts = toTags(raw, separator)\n setInput('')\n if (!parts.length) return\n const next = [...tags]\n for (const part of parts) {\n if (!allowDuplicates && next.includes(part)) continue\n next.push(part)\n }\n if (next.length !== tags.length) commit(next)\n }\n\n const removeTag = (index: number) => {\n commit(tags.filter((_, i) => i !== index))\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // while an IME is composing (CJK etc.), Enter/separator confirm the candidate — not a commit\n if (event.nativeEvent.isComposing) {\n onKeyDown?.(event)\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n addTags(input)\n } else if (separator.length === 1 && event.key === separator) {\n event.preventDefault()\n addTags(input)\n } else if (event.key === 'Backspace' && input === '' && tags.length > 0) {\n event.preventDefault()\n removeTag(tags.length - 1)\n }\n onKeyDown?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n if (input.trim()) addTags(input) // don't lose a typed-but-not-committed tag\n bound?.onBlur(event)\n onBlur?.(event)\n }\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {\n const text = event.clipboardData.getData('text')\n if (text && separator && text.includes(separator)) {\n event.preventDefault()\n // splice the pasted, separator-delimited text into the input at the caret/selection\n const el = event.currentTarget\n const start = el.selectionStart ?? input.length\n const end = el.selectionEnd ?? input.length\n addTags(input.slice(0, start) + text + input.slice(end))\n }\n onPaste?.(event)\n }\n\n return (\n <div\n className={clsx(\n styles.field,\n styles[size],\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style as CSSProperties}\n >\n {label != null && (\n <label htmlFor={id} className={styles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={styles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div className={styles.control}>\n {/* clicking anywhere in the tag area focuses the input */}\n <div\n className={clsx(styles.tags, tags.length > 0 && styles.tagsFilled)}\n onClick={() => inputRef.current?.focus()}\n >\n {tags.map((tag, index) => (\n <Chip\n key={`${tag}-${index}`}\n size={size}\n color={color}\n disabled={disabled}\n onDelete={() => removeTag(index)}\n deleteLabel={`Remove ${tag}`}\n >\n {tag}\n </Chip>\n ))}\n <input\n ref={setRef}\n id={id}\n name={name}\n className={styles.input}\n value={input}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n aria-invalid={resolvedError || undefined}\n aria-describedby={resolvedHelperText != null ? helperId : undefined}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onPaste={handlePaste}\n {...props}\n />\n </div>\n <IconButton\n type=\"button\"\n variant=\"text\"\n color=\"primary\"\n size={size}\n disabled={disabled || input.trim() === ''}\n aria-label={addLabel ?? t('tagsField.add')}\n className={styles.addButton}\n // keep the input's focus ring while clicking add (don't steal focus → blur → double add)\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => addTags(input)}\n >\n {addIcon ?? <Icon name=\"Add\" />}\n </IconButton>\n </div>\n\n {resolvedHelperText != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={resolvedError ? 'error' : 'muted'}\n className={styles.helper}\n >\n {resolvedHelperText}\n </Typography>\n )}\n </div>\n )\n})\n"],"names":["toTags","value","separator","t","TagsField","forwardRef","label","size","error","helperText","required","fullWidth","disabled","defaultValue","onChange","color","allowDuplicates","placeholder","addIcon","addLabel","name","idProp","className","style","onKeyDown","onBlur","onPaste","props","ref","reactId","useId","id","helperId","form","useFormContext","isFormBound","bound","rawFormValue","resolvedError","resolvedHelperText","externalValue","isControlled","useT","stringMode","internal","setInternal","useState","tags","input","setInput","inputRef","useRef","setRef","useCallback","node","commit","nextTags","out","addTags","raw","parts","next","part","removeTag","index","_","i","handleKeyDown","event","handleBlur","handlePaste","text","el","start","end","jsxs","clsx","styles","jsx","Typography","_a","tag","Chip","IconButton","Icon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAASA,EAAOC,GAAsCC,GAA6B;AAQjF,UAPc,MAAM,QAAQD,CAAK,IAC7BA,IACA,OAAOA,KAAU,WACfC,IACED,EAAM,MAAMC,CAAS,IACrB,CAACD,CAAK,IACR,CAAA,GACO,IAAI,CAACE,MAAMA,EAAE,KAAA,CAAM,EAAE,OAAO,OAAO;AAClD;AAiDO,MAAMC,KAAYC,GAA6C,SACpE;AAAA,EACE,OAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,OAAAC;AAAA,EACA,YAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,UAAAC,IAAW;AAAA,EACX,OAAAX;AAAA,EACA,cAAAY;AAAA,EACA,UAAAC;AAAA,EACA,WAAAZ,IAAY;AAAA,EACZ,OAAAa,IAAQ;AAAA,EACR,iBAAAC,IAAkB;AAAA,EAClB,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;AAAA,EACA,MAAAC;AAAA,EACA,IAAIC;AAAA,EACJ,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,QAAMC,IAAUC,GAAA,GACVC,IAAKV,KAAUQ,GACfG,IAAW,GAAGD,CAAE,WAKhBE,IAAOC,GAAA,GACPC,IAAc,GAAQF,KAAQb,IAC9BgB,IAAQD,IAAcF,EAAM,MAAMb,CAAK,IAAI,QAC3CiB,KAAeF,IAChBF,EAAM,OAAOb,CAAK,IACnB,QAEEkB,IAAgB9B,MAAS4B,KAAA,gBAAAA,EAAO,UAAS,IACzCG,IAAqB9B,MAAc2B,KAAA,gBAAAA,EAAO,aAE1CI,IAAgBvC,MAAU,SAAYA,IAAQkC,IAAcE,KAAe,QAC3EI,IAAexC,MAAU,UAAakC,GAEtChC,KAAIuC,GAAA,GAEJC,KAAa,QADCH,MAAkB,SAAYA,IAAgB3B,MACxB,UAEpC,CAAC+B,IAAUC,EAAW,IAAIC,EAAmB,MAAM9C,EAAOa,GAAcX,CAAS,CAAC,GAClF6C,IAAON,IAAezC,EAAOwC,GAAetC,CAAS,IAAI0C,IAEzD,CAACI,GAAOC,CAAQ,IAAIH,EAAS,EAAE,GAE/BI,IAAWC,GAAgC,IAAI,GAC/CC,KAASC;AAAA,IACb,CAACC,MAAkC;AACjC,MAAAJ,EAAS,UAAUI,GACf,OAAO1B,KAAQ,aAAYA,EAAI0B,CAAI,IAC9B1B,MAAMA,EAA6C,UAAU0B;AAAA,IACxE;AAAA,IACA,CAAC1B,CAAG;AAAA,EAAA,GAGA2B,IAAS,CAACC,MAAuB;AACrC,IAAKf,KAAcI,GAAYW,CAAQ;AACvC,UAAMC,IAAyBd,KAAaa,EAAS,KAAKtD,CAAS,IAAIsD;AACvE,IAAIrB,KAAaF,EAAM,SAASb,GAAOqC,CAAG,GAC1C3C,KAAA,QAAAA,EAAW2C;AAAA,EACb,GAEMC,IAAU,CAACC,MAAgB;AAC/B,UAAMC,IAAQ5D,EAAO2D,GAAKzD,CAAS;AAEnC,QADA+C,EAAS,EAAE,GACP,CAACW,EAAM,OAAQ;AACnB,UAAMC,IAAO,CAAC,GAAGd,CAAI;AACrB,eAAWe,KAAQF;AACjB,MAAI,CAAC5C,KAAmB6C,EAAK,SAASC,CAAI,KAC1CD,EAAK,KAAKC,CAAI;AAEhB,IAAID,EAAK,WAAWd,EAAK,YAAec,CAAI;AAAA,EAC9C,GAEME,IAAY,CAACC,MAAkB;AACnC,IAAAT,EAAOR,EAAK,OAAO,CAACkB,GAAGC,MAAMA,MAAMF,CAAK,CAAC;AAAA,EAC3C,GAEMG,KAAgB,CAACC,MAA2C;AAEhE,QAAIA,EAAM,YAAY,aAAa;AACjC,MAAA5C,KAAA,QAAAA,EAAY4C;AACZ;AAAA,IACF;AACA,IAAIA,EAAM,QAAQ,WAGPlE,EAAU,WAAW,KAAKkE,EAAM,QAAQlE,KAFjDkE,EAAM,eAAA,GACNV,EAAQV,CAAK,KAIJoB,EAAM,QAAQ,eAAepB,MAAU,MAAMD,EAAK,SAAS,MACpEqB,EAAM,eAAA,GACNL,EAAUhB,EAAK,SAAS,CAAC,IAE3BvB,KAAA,QAAAA,EAAY4C;AAAA,EACd,GAEMC,KAAa,CAACD,MAAwC;AAC1D,IAAIpB,EAAM,UAAQU,EAAQV,CAAK,GAC/BZ,KAAA,QAAAA,EAAO,OAAOgC,IACd3C,KAAA,QAAAA,EAAS2C;AAAA,EACX,GAEME,KAAc,CAACF,MAA4C;AAC/D,UAAMG,IAAOH,EAAM,cAAc,QAAQ,MAAM;AAC/C,QAAIG,KAAQrE,KAAaqE,EAAK,SAASrE,CAAS,GAAG;AACjD,MAAAkE,EAAM,eAAA;AAEN,YAAMI,IAAKJ,EAAM,eACXK,IAAQD,EAAG,kBAAkBxB,EAAM,QACnC0B,KAAMF,EAAG,gBAAgBxB,EAAM;AACrC,MAAAU,EAAQV,EAAM,MAAM,GAAGyB,CAAK,IAAIF,IAAOvB,EAAM,MAAM0B,EAAG,CAAC;AAAA,IACzD;AACA,IAAAhD,KAAA,QAAAA,EAAU0C;AAAA,EACZ;AAEA,SACE,gBAAAO;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACTC,EAAO;AAAA,QACPA,EAAOtE,CAAI;AAAA,QACXI,KAAakE,EAAO;AAAA,QACpBvC,KAAiBuC,EAAO;AAAA,QACxBjE,KAAYiE,EAAO;AAAA,QACnBvD;AAAA,MAAA;AAAA,MAEF,OAAAC;AAAA,MAEC,UAAA;AAAA,QAAAjB,KAAS,QACR,gBAAAqE,EAAC,SAAA,EAAM,SAAS5C,GAAI,WAAW8C,EAAO,OACpC,UAAA;AAAA,UAAA,gBAAAC,EAACC,KAAW,IAAG,QAAO,SAAQ,aAAY,OAAM,SAC7C,UAAAzE,EAAA,CACH;AAAA,UACCI,uBACE,QAAA,EAAK,WAAWmE,EAAO,UAAU,eAAY,QAAO,UAAA,IAAA,CAErD;AAAA,QAAA,GAEJ;AAAA,QAGF,gBAAAF,EAAC,OAAA,EAAI,WAAWE,EAAO,SAErB,UAAA;AAAA,UAAA,gBAAAF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWC,EAAKC,EAAO,MAAM9B,EAAK,SAAS,KAAK8B,EAAO,UAAU;AAAA,cACjE,SAAS,MAAA;;AAAM,wBAAAG,IAAA9B,EAAS,YAAT,gBAAA8B,EAAkB;AAAA;AAAA,cAEhC,UAAA;AAAA,gBAAAjC,EAAK,IAAI,CAACkC,GAAKjB,MACd,gBAAAc;AAAA,kBAACI;AAAA,kBAAA;AAAA,oBAEC,MAAA3E;AAAA,oBACA,OAAAQ;AAAA,oBACA,UAAAH;AAAA,oBACA,UAAU,MAAMmD,EAAUC,CAAK;AAAA,oBAC/B,aAAa,UAAUiB,CAAG;AAAA,oBAEzB,UAAAA;AAAA,kBAAA;AAAA,kBAPI,GAAGA,CAAG,IAAIjB,CAAK;AAAA,gBAAA,CASvB;AAAA,gBACD,gBAAAc;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,KAAK1B;AAAA,oBACL,IAAArB;AAAA,oBACA,MAAAX;AAAA,oBACA,WAAWyD,EAAO;AAAA,oBAClB,OAAO7B;AAAA,oBACP,aAAaD,EAAK,WAAW,IAAI9B,IAAc;AAAA,oBAC/C,UAAAL;AAAA,oBACA,gBAAc0B,KAAiB;AAAA,oBAC/B,oBAAkBC,KAAsB,OAAOP,IAAW;AAAA,oBAC1D,UAAU,CAACoC,MAAUnB,EAASmB,EAAM,OAAO,KAAK;AAAA,oBAChD,WAAWD;AAAA,oBACX,QAAQE;AAAA,oBACR,SAASC;AAAA,oBACR,GAAG3C;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACN;AAAA,YAAA;AAAA,UAAA;AAAA,UAEF,gBAAAmD;AAAA,YAACK;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,MAAA5E;AAAA,cACA,UAAUK,KAAYoC,EAAM,KAAA,MAAW;AAAA,cACvC,cAAY7B,KAAYhB,GAAE,eAAe;AAAA,cACzC,WAAW0E,EAAO;AAAA,cAElB,aAAa,CAACT,MAAUA,EAAM,eAAA;AAAA,cAC9B,SAAS,MAAMV,EAAQV,CAAK;AAAA,cAE3B,UAAA9B,KAAW,gBAAA4D,EAACM,IAAA,EAAK,MAAK,MAAA,CAAM;AAAA,YAAA;AAAA,UAAA;AAAA,QAC/B,GACF;AAAA,QAEC7C,KAAsB,QACrB,gBAAAuC;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,IAAG;AAAA,YACH,IAAI/C;AAAA,YACJ,SAAQ;AAAA,YACR,OAAOM,IAAgB,UAAU;AAAA,YACjC,WAAWuC,EAAO;AAAA,YAEjB,UAAAtC;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR,CAAC;"}
|
|
1
|
+
{"version":3,"file":"TagsField-Bvh6Fm5Y.js","sources":["../src/components/TagsField/TagsField.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useId,\n useRef,\n useState,\n type ClipboardEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { useFormContext } from '../../form/formContext'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Chip } from '../Chip'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Typography } from '../Typography'\nimport styles from './TagsField.module.css'\n\nexport type TagsFieldSize = 'sm' | 'md' | 'lg'\n\n/** Splits a value (array or `separator`-joined string) into trimmed, non-empty tags. */\nfunction toTags(value: string[] | string | undefined, separator: string): string[] {\n const parts = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? separator\n ? value.split(separator)\n : [value] // empty separator → don't explode into per-character tags\n : []\n return parts.map((t) => t.trim()).filter(Boolean)\n}\n\nexport interface TagsFieldProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'color' | 'value' | 'defaultValue' | 'onChange'\n> {\n /** Label rendered above the field. */\n label?: ReactNode\n /** Preset size — control height, font and chips. */\n size?: TagsFieldSize\n /** Marks the field invalid: red border/focus ring and the `helperText` shown in the error color. */\n error?: boolean\n /** Helper / validation text under the field. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the field to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /** Disables the field (no typing, no add/remove). */\n disabled?: boolean\n /** Controlled value — a `string[]` or a `separator`-joined `string` (e.g. `\"react;typescript\"`). */\n value?: string[] | string\n /** Initial value for uncontrolled use (`string[]` or a joined `string`). */\n defaultValue?: string[] | string\n /** Fires with the next tags, mirroring the input shape: a `string[]`, or a joined `string` when the value is a string. */\n onChange?: (value: string[] | string) => void\n /** Character/string that splits typed & pasted input and joins the value when it's a string. Defaults to `,`. */\n separator?: string\n /** Theme palette token tinting the tag chips. Defaults to `primary`. */\n color?: ThemeColor\n /** Allow the same tag more than once. Off by default (duplicates are ignored). */\n allowDuplicates?: boolean\n /** Placeholder shown in the input while there are no tags. */\n placeholder?: string\n /** Icon for the add button. Defaults to an `Add` icon. */\n addIcon?: ReactNode\n /** Accessible label for the add button. Defaults to `\"Add tag\"`. */\n addLabel?: string\n}\n\n/**\n * A tags / token input. Type a value and press **Enter**, the **add button**, or the `separator`\n * key to commit it as a tag; remove a tag via its chip's delete button (or Backspace on the empty\n * input). The **`separator`** (default `,`) also splits pasted text, so pasting `\"react;typescript\"`\n * (with `separator=\";\"`) adds both at once. The value accepts — and `onChange` mirrors — **either a\n * `string[]` or a `separator`-joined `string`**, so it binds to a `<Form>` schema of either shape.\n * Shares TextField's chrome (label, helper/error, sizes, `<Form>` binding by `name` for validation).\n * Controlled (`value` + `onChange`) or uncontrolled (`defaultValue`). Token-only styling.\n */\nexport const TagsField = forwardRef<HTMLInputElement, TagsFieldProps>(function TagsField(\n {\n label,\n size = 'md',\n error,\n helperText,\n required = false,\n fullWidth = true,\n disabled = false,\n value,\n defaultValue,\n onChange,\n separator = ',',\n color = 'primary',\n allowDuplicates = false,\n placeholder,\n addIcon,\n addLabel,\n name,\n id: idProp,\n className,\n style,\n onKeyDown,\n onBlur,\n onPaste,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n // Auto-bind to a surrounding <Form> by `name`. error/helper/onBlur come from field(), but the VALUE\n // is read RAW from `form.values` — field().value is always String-coerced, which would flatten a\n // `string[]` into a joined string and break an array schema. Same pattern as NumberField/ColorPicker.\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = isFormBound ? form!.field(name!) : undefined\n const rawFormValue = isFormBound\n ? (form!.values[name!] as string[] | string | undefined)\n : undefined\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n\n const externalValue = value !== undefined ? value : isFormBound ? rawFormValue : undefined\n const isControlled = value !== undefined || isFormBound\n // Mirror the value's shape on output: a joined string when the source is a string, else an array.\n const t = useT()\n const shapeSource = externalValue !== undefined ? externalValue : defaultValue\n const stringMode = typeof shapeSource === 'string'\n\n const [internal, setInternal] = useState<string[]>(() => toTags(defaultValue, separator))\n const tags = isControlled ? toTags(externalValue, separator) : internal\n\n const [input, setInput] = useState('')\n\n const inputRef = useRef<HTMLInputElement | null>(null)\n const setRef = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as { current: HTMLInputElement | null }).current = node\n },\n [ref],\n )\n\n const commit = (nextTags: string[]) => {\n if (!isControlled) setInternal(nextTags)\n const out: string[] | string = stringMode ? nextTags.join(separator) : nextTags\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n const addTags = (raw: string) => {\n const parts = toTags(raw, separator)\n setInput('')\n if (!parts.length) return\n const next = [...tags]\n for (const part of parts) {\n if (!allowDuplicates && next.includes(part)) continue\n next.push(part)\n }\n if (next.length !== tags.length) commit(next)\n }\n\n const removeTag = (index: number) => {\n commit(tags.filter((_, i) => i !== index))\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // while an IME is composing (CJK etc.), Enter/separator confirm the candidate — not a commit\n if (event.nativeEvent.isComposing) {\n onKeyDown?.(event)\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n addTags(input)\n } else if (separator.length === 1 && event.key === separator) {\n event.preventDefault()\n addTags(input)\n } else if (event.key === 'Backspace' && input === '' && tags.length > 0) {\n event.preventDefault()\n removeTag(tags.length - 1)\n }\n onKeyDown?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n if (input.trim()) addTags(input) // don't lose a typed-but-not-committed tag\n bound?.onBlur(event)\n onBlur?.(event)\n }\n\n const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {\n const text = event.clipboardData.getData('text')\n if (text && separator && text.includes(separator)) {\n event.preventDefault()\n // splice the pasted, separator-delimited text into the input at the caret/selection\n const el = event.currentTarget\n const start = el.selectionStart ?? input.length\n const end = el.selectionEnd ?? input.length\n addTags(input.slice(0, start) + text + input.slice(end))\n }\n onPaste?.(event)\n }\n\n return (\n <div\n className={clsx(\n styles.field,\n styles[size],\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style as CSSProperties}\n >\n {label != null && (\n <label htmlFor={id} className={styles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={styles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div className={styles.control}>\n {/* clicking anywhere in the tag area focuses the input */}\n <div\n className={clsx(styles.tags, tags.length > 0 && styles.tagsFilled)}\n onClick={() => inputRef.current?.focus()}\n >\n {tags.map((tag, index) => (\n <Chip\n key={`${tag}-${index}`}\n size={size}\n color={color}\n disabled={disabled}\n onDelete={() => removeTag(index)}\n deleteLabel={`Remove ${tag}`}\n >\n {tag}\n </Chip>\n ))}\n <input\n ref={setRef}\n id={id}\n name={name}\n className={styles.input}\n value={input}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n aria-invalid={resolvedError || undefined}\n aria-describedby={resolvedHelperText != null ? helperId : undefined}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onPaste={handlePaste}\n {...props}\n />\n </div>\n <IconButton\n type=\"button\"\n variant=\"text\"\n color=\"primary\"\n size={size}\n disabled={disabled || input.trim() === ''}\n aria-label={addLabel ?? t('tagsField.add')}\n className={styles.addButton}\n // keep the input's focus ring while clicking add (don't steal focus → blur → double add)\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => addTags(input)}\n >\n {addIcon ?? <Icon name=\"Add\" />}\n </IconButton>\n </div>\n\n {resolvedHelperText != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={resolvedError ? 'error' : 'muted'}\n className={styles.helper}\n >\n {resolvedHelperText}\n </Typography>\n )}\n </div>\n )\n})\n"],"names":["toTags","value","separator","t","TagsField","forwardRef","label","size","error","helperText","required","fullWidth","disabled","defaultValue","onChange","color","allowDuplicates","placeholder","addIcon","addLabel","name","idProp","className","style","onKeyDown","onBlur","onPaste","props","ref","reactId","useId","id","helperId","form","useFormContext","isFormBound","bound","rawFormValue","resolvedError","resolvedHelperText","externalValue","isControlled","useT","stringMode","internal","setInternal","useState","tags","input","setInput","inputRef","useRef","setRef","useCallback","node","commit","nextTags","out","addTags","raw","parts","next","part","removeTag","index","_","i","handleKeyDown","event","handleBlur","handlePaste","text","el","start","end","jsxs","clsx","styles","jsx","Typography","_a","tag","Chip","IconButton","Icon"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const r=require("react/jsx-runtime"),d=require("react"),X=require("clsx"),Re=require("./formContext-bTWrqdEV.cjs"),Y=require("./Icon-
|
|
2
|
-
//# sourceMappingURL=TextField-
|
|
1
|
+
"use strict";const r=require("react/jsx-runtime"),d=require("react"),X=require("clsx"),Re=require("./formContext-bTWrqdEV.cjs"),Y=require("./Icon-BVULqOJD.cjs"),U=require("./IconButton-Lv0sDDR9.cjs"),T=require("./Typography-BFatE1_A.cjs"),s=require("./TextField.module-m-UllwzG.cjs"),qe=require("./ConfigProvider-C7DUWHrb.cjs"),ee={9:/[0-9]/,a:/[A-Za-z]/,"*":/[A-Za-z0-9]/};function Be(t,n){let o="",l=0;for(const c of n){const p=ee[c];if(p){for(;l<t.length&&!p.test(t[l]);)l++;if(l>=t.length)break;o+=t[l],l++}else{if(l>=t.length)break;t[l]===c&&l++,o+=c}}return o}function ke(t,n){const o=new Set([...n].filter(l=>!ee[l]));return[...t].filter(l=>!o.has(l)).join("")}const Ee=/[A-Za-z0-9]/;function Me(t,n){const o=(t.match(/[A-Za-z0-9]/g)??[]).length;if(o<=0)return 0;let l=0;for(let c=0;c<n.length;c++)if(Ee.test(n[c])&&(l+=1,l===o))return c+1;return n.length}function Pe(t){if(!t)return 0;let n=0;return t.length>=8&&(n+=1),/[a-z]/.test(t)&&/[A-Z]/.test(t)&&(n+=1),/\d/.test(t)&&(n+=1),/[^A-Za-z0-9]/.test(t)&&(n+=1),n}function ze(t){return t<=0?null:t===1?"weak":t===2?"medium":"strong"}const I={weak:{labelKey:"textField.strengthWeak",color:"error",bars:1},medium:{labelKey:"textField.strengthMedium",color:"warning",bars:2},strong:{labelKey:"textField.strengthStrong",color:"success",bars:3}},Le=d.forwardRef(function({label:n,size:o="md",error:l,helperText:c,required:p=!1,fullWidth:te=!0,adornment:se,adornmentPosition:le="left",onAdornmentClick:re,adornmentLabel:ne,regex:Z,mask:S,passwordToggle:ie=!0,capsLockWarning:b=!1,passwordStrength:oe=!1,name:F,value:C,defaultValue:w,onChange:R,onBlur:q,onFocus:ae,onKeyDown:B,onKeyUp:k,disabled:j=!1,type:O,id:ce,className:de,style:fe,...ue},h){const y=qe.useT(),he=d.useId(),m=ce??he,$=`${m}-helper`,_=Re.useFormContext(),i=_&&F?_.field(F):void 0,E=l??(i==null?void 0:i.error)??!1,M=c??(i==null?void 0:i.helperText),ye=C!==void 0||i!==void 0,[me,ge]=d.useState(w!=null?String(w):""),G=C!==void 0?C:i?i.value:me,H=d.useRef(null),xe=d.useCallback(e=>{H.current=e,typeof h=="function"?h(e):h&&(h.current=e)},[h]),v=d.useRef(null);d.useLayoutEffect(()=>{var a;const e=v.current;e!=null&&(v.current=null,(a=H.current)==null||a.setSelectionRange(e,e))});const pe=e=>{const a=e.target;let u=a.value;if(S){const L=a.selectionStart??a.value.length,Ce=a.value.slice(0,L);u=Be(u,S),v.current=Me(Ce,u)}if(Z){const L=S?ke(u,S):u;if(!Z.test(L)){v.current=null;return}}ye||ge(u),a.value=u,i==null||i.onChange(e),R==null||R(e)},Se=e=>{D(!1),i==null||i.onBlur(e),q==null||q(e)},[K,D]=d.useState(!1),J=e=>{var a;b&&D(((a=e.getModifierState)==null?void 0:a.call(e,"CapsLock"))??!1)},je=e=>{J(e),B==null||B(e)},ve=e=>{J(e),k==null||k(e)},[P,Ae]=d.useState(!1),Q=O==="password",A=Q&&ie,Ne=Q&&P?"text":O,f=A?r.jsx(Y.Icon,{name:P?"EyeSlash":"Eye"}):se,N=A?"right":le,V=A?()=>Ae(e=>!e):re,Te=A?y(P?"textField.hidePassword":"textField.showPassword"):ne??y("textField.fieldAction"),g=oe?ze(Pe(String(G??""))):null,Ie=`${m}-strength`,W=`${m}-caps`,be=[M!=null?$:null,b&&K?W:null].filter(Boolean).join(" ")||void 0,z=f!=null&&f!==!1,Fe=typeof f=="string"||typeof f=="number";let x=null;return z&&(Fe?x=r.jsx("span",{className:s.fieldStyles.textAdornment,children:f}):V?x=r.jsx(U.IconButton,{variant:"text",color:"primary",size:o,disabled:j,"aria-label":Te,onClick:V,onMouseDown:e=>e.preventDefault(),className:s.fieldStyles.iconButton,children:f}):x=r.jsx(U.IconButton,{variant:"text",color:"primary",size:o,disabled:j,nonClickable:!0,"aria-hidden":"true",className:s.fieldStyles.iconButton,children:f})),r.jsxs("div",{className:X.clsx(s.fieldStyles.field,s.fieldStyles[o],te&&s.fieldStyles.fullWidth,E&&s.fieldStyles.error,j&&s.fieldStyles.disabled,de),style:fe,children:[n!=null&&r.jsxs("label",{htmlFor:m,className:s.fieldStyles.label,children:[r.jsx(T.Typography,{as:"span",variant:"bodySmall",color:"muted",children:n}),p&&r.jsx("span",{className:s.fieldStyles.required,"aria-hidden":"true",children:"*"})]}),r.jsxs("div",{className:X.clsx(s.fieldStyles.control,z&&N==="left"&&s.fieldStyles.hasLeftAdornment,z&&N==="right"&&s.fieldStyles.hasRightAdornment),children:[N==="left"&&x,r.jsx("input",{ref:xe,id:m,name:F,type:Ne,className:s.fieldStyles.input,value:G,onChange:pe,onBlur:Se,onFocus:ae,onKeyDown:je,onKeyUp:ve,disabled:j,"aria-invalid":E||void 0,"aria-describedby":be,...ue}),N==="right"&&x]}),b&&K&&r.jsxs(T.Typography,{as:"span",id:W,variant:"bodySmall",color:"warning",className:s.fieldStyles.caps,role:"alert",children:[r.jsx(Y.Icon,{name:"Danger"}),y("textField.capsLock")]}),g&&r.jsxs("div",{className:s.fieldStyles.strength,style:{"--tz-strength-color":`var(--tz-color-${I[g].color})`},children:[r.jsx("span",{className:s.fieldStyles.strengthBars,"aria-hidden":"true",children:[0,1,2].map(e=>r.jsx("span",{className:s.fieldStyles.strengthBar,"data-on":e<I[g].bars},e))}),r.jsx(T.Typography,{as:"span",id:Ie,variant:"bodySmall",color:I[g].color,className:s.fieldStyles.strengthLabel,children:y(I[g].labelKey)})]}),M!=null&&r.jsx(T.Typography,{as:"span",id:$,variant:"bodySmall",color:E?"error":"muted",className:s.fieldStyles.helper,children:M})]})});exports.TextField=Le;
|
|
2
|
+
//# sourceMappingURL=TextField-DNqnpAWB.cjs.map
|