@robot-admin/naive-ui-components 0.8.1 → 0.8.2
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/README.md +279 -279
- package/dist/C_ActionBar-DYG0Yf3A.css.map +1 -0
- package/dist/C_ActionBar-MAjRhqcI.css.map +1 -0
- package/dist/C_ActionBar.cjs +1 -1
- package/dist/C_ActionBar.css +47 -47
- package/dist/C_ActionBar.js +1 -1
- package/dist/C_ActionBar.js.map +1 -1
- package/dist/C_ActionBar2.js +1 -1
- package/dist/C_ActionBar2.js.map +1 -1
- package/dist/{C_AntV-A3NXx_sF.css.map → C_AntV-BY8jqqmi.css.map} +1 -1
- package/dist/{C_AntV-D2Zp2qQF.css.map → C_AntV-BbkHc-_a.css.map} +1 -1
- package/dist/C_AntV.cjs +1 -1
- package/dist/C_AntV.css +78 -78
- package/dist/C_AntV.js +1 -1
- package/dist/C_AntV.js.map +1 -1
- package/dist/C_AntV2.js +3 -3
- package/dist/C_AntV2.js.map +1 -1
- package/dist/{C_AudioPlayer-CXl4yP_m.css.map → C_AudioPlayer-DKRIGhi7.css.map} +1 -1
- package/dist/{C_AudioPlayer-CcBtt71m.css.map → C_AudioPlayer-DlB6eNsa.css.map} +1 -1
- package/dist/C_AudioPlayer.cjs +1 -1
- package/dist/C_AudioPlayer.css +47 -47
- package/dist/C_AudioPlayer.js +1 -1
- package/dist/C_AudioPlayer.js.map +1 -1
- package/dist/C_AudioPlayer2.js +1 -1
- package/dist/C_AudioPlayer2.js.map +1 -1
- package/dist/{C_AvatarGroup-CtPhfH9h.css.map → C_AvatarGroup-D02zci-i.css.map} +1 -1
- package/dist/{C_AvatarGroup-M1dNPH3E.css.map → C_AvatarGroup-DatHaUlY.css.map} +1 -1
- package/dist/C_AvatarGroup.css +21 -21
- package/dist/C_AvatarGroup.js.map +1 -1
- package/dist/C_AvatarGroup2.js +1 -1
- package/dist/C_AvatarGroup2.js.map +1 -1
- package/dist/{C_Barcode-DjTmDkbQ.css.map → C_Barcode-DYDRDe2O.css.map} +1 -1
- package/dist/{C_Barcode-Do1Ozsmh.css.map → C_Barcode-muJdc_O4.css.map} +1 -1
- package/dist/C_Barcode.css +7 -7
- package/dist/C_Barcode.js.map +1 -1
- package/dist/C_Barcode2.js +1 -1
- package/dist/C_Barcode2.js.map +1 -1
- package/dist/C_Breadcrumb.cjs +1 -1
- package/dist/C_Breadcrumb.js +1 -1
- package/dist/C_Breadcrumb.js.map +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/{C_Captcha-CZmAETly.css.map → C_Captcha-9_hk6VmY.css.map} +1 -1
- package/dist/{C_Captcha-Ccq3DMrR.css.map → C_Captcha-MtASlJ0f.css.map} +1 -1
- package/dist/C_Captcha.css +19 -19
- package/dist/C_Captcha.js.map +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Captcha2.js.map +1 -1
- package/dist/C_Cascade.js.map +1 -1
- package/dist/C_Cascade2.js +1 -1
- package/dist/C_Cascade2.js.map +1 -1
- package/dist/{C_Chat-CJ8KESTM.css.map → C_Chat-Csjz_BFw.css.map} +1 -1
- package/dist/{C_Chat-DzV4AFLd.css.map → C_Chat-DO1ZBA_0.css.map} +1 -1
- package/dist/C_Chat.cjs +1 -1
- package/dist/C_Chat.css +65 -65
- package/dist/C_Chat.js +1 -1
- package/dist/C_Chat.js.map +1 -1
- package/dist/C_Chat2.js +1 -1
- package/dist/C_Chat2.js.map +1 -1
- package/dist/{C_City-Cv5BESaN.css.map → C_City-Bam08Qv3.css.map} +1 -1
- package/dist/{C_City-DNKv4MpH.css.map → C_City-Bb3W-KaN.css.map} +1 -1
- package/dist/C_City.css +29 -29
- package/dist/C_City.js.map +1 -1
- package/dist/C_City2.js +1 -1
- package/dist/C_City2.js.map +1 -1
- package/dist/C_Code-BFi5xxnM.css.map +1 -0
- package/dist/C_Code-CZ7yfnri.css.map +1 -0
- package/dist/C_Code.cjs +1 -1
- package/dist/C_Code.css +3 -3
- package/dist/C_Code.js +1 -1
- package/dist/C_Code.js.map +1 -1
- package/dist/C_Code2.js +1 -1
- package/dist/C_Code2.js.map +1 -1
- package/dist/{C_CollapsePanel-CedsEM0N.css.map → C_CollapsePanel-CWkFCqNQ.css.map} +1 -1
- package/dist/{C_CollapsePanel-BkOivqn3.css.map → C_CollapsePanel-pcVJA_4z.css.map} +1 -1
- package/dist/C_CollapsePanel.cjs +1 -1
- package/dist/C_CollapsePanel.css +35 -35
- package/dist/C_CollapsePanel.js +1 -1
- package/dist/C_CollapsePanel.js.map +1 -1
- package/dist/C_CollapsePanel2.js +1 -1
- package/dist/C_CollapsePanel2.js.map +1 -1
- package/dist/{C_ContextMenu-CCsCeI39.css.map → C_ContextMenu-B3Cgz_wJ.css.map} +1 -1
- package/dist/{C_ContextMenu-DOTBeltf.css.map → C_ContextMenu-u1LixF3_.css.map} +1 -1
- package/dist/C_ContextMenu.cjs +1 -1
- package/dist/C_ContextMenu.css +17 -17
- package/dist/C_ContextMenu.js +1 -1
- package/dist/C_ContextMenu.js.map +1 -1
- package/dist/C_ContextMenu2.js +1 -1
- package/dist/C_ContextMenu2.js.map +1 -1
- package/dist/{C_Cron-C0-8b5af.css.map → C_Cron-Civir5-I.css.map} +1 -1
- package/dist/{C_Cron-DqHQ92LN.css.map → C_Cron-iw3qpMsy.css.map} +1 -1
- package/dist/C_Cron.cjs +1 -1
- package/dist/C_Cron.css +37 -37
- package/dist/C_Cron.js +1 -1
- package/dist/C_Cron.js.map +1 -1
- package/dist/C_Cron2.js +1 -1
- package/dist/C_Cron2.js.map +1 -1
- package/dist/C_Date.js.map +1 -1
- package/dist/C_Date2.js +1 -1
- package/dist/C_Date2.js.map +1 -1
- package/dist/{C_Draggable-Bq6o0qXn.css.map → C_Draggable-BCjIvIwT.css.map} +1 -1
- package/dist/{C_Draggable-r6nhx3yM.css.map → C_Draggable-DwkSlCOS.css.map} +1 -1
- package/dist/C_Draggable.css +46 -46
- package/dist/C_Draggable.js.map +1 -1
- package/dist/C_Draggable2.js +1 -1
- package/dist/C_Draggable2.js.map +1 -1
- package/dist/C_Editor-BfjjYQ9B.css.map +1 -0
- package/dist/C_Editor-Do2StvoJ.css.map +1 -0
- package/dist/C_Editor.css +55 -55
- package/dist/C_Editor.js.map +1 -1
- package/dist/C_Editor2.js +1 -1
- package/dist/C_Editor2.js.map +1 -1
- package/dist/{C_FilePreview-BVarVvnD.css.map → C_FilePreview-BhcbiXsV.css.map} +1 -1
- package/dist/{C_FilePreview-DHGlV4OR.css.map → C_FilePreview-DJudcIbW.css.map} +1 -1
- package/dist/C_FilePreview.cjs +1 -1
- package/dist/C_FilePreview.css +91 -91
- package/dist/C_FilePreview.js +1 -1
- package/dist/C_FilePreview.js.map +1 -1
- package/dist/C_FilePreview2.js +1 -1
- package/dist/C_FilePreview2.js.map +1 -1
- package/dist/{C_Form-BciQUPpS.css.map → C_Form-BtcAPIRi.css.map} +1 -1
- package/dist/{C_Form-CKHvXL3O.css.map → C_Form-D_gwQ7hC.css.map} +1 -1
- package/dist/C_Form.cjs +1 -1
- package/dist/C_Form.css +222 -222
- package/dist/C_Form.js +1 -1
- package/dist/C_Form.js.map +1 -1
- package/dist/C_Form2.js +1 -1
- package/dist/C_Form2.js.map +1 -1
- package/dist/{C_FormSearch-Bmd2CmG6.css.map → C_FormSearch-Bi4XYjjk.css.map} +1 -1
- package/dist/{C_FormSearch-DBNtnjaL.css.map → C_FormSearch-DUGOoX0u.css.map} +1 -1
- package/dist/C_FormSearch.css +45 -45
- package/dist/C_FormSearch.js.map +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormSearch2.js.map +1 -1
- package/dist/{C_FormulaEditor-3WG2vtQl.css.map → C_FormulaEditor-CJk3SSUJ.css.map} +1 -1
- package/dist/{C_FormulaEditor-Cm0CokN5.css.map → C_FormulaEditor-Cy7mjfVO.css.map} +1 -1
- package/dist/C_FormulaEditor.cjs +1 -1
- package/dist/C_FormulaEditor.css +78 -78
- package/dist/C_FormulaEditor.js +1 -1
- package/dist/C_FormulaEditor.js.map +1 -1
- package/dist/C_FormulaEditor2.js +1 -1
- package/dist/C_FormulaEditor2.js.map +1 -1
- package/dist/C_FullCalendar-BQA0OjGB.css.map +1 -0
- package/dist/C_FullCalendar-ChJUosAi.css.map +1 -0
- package/dist/C_FullCalendar.css +3 -3
- package/dist/C_FullCalendar.js.map +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_FullCalendar2.js.map +1 -1
- package/dist/C_GlobalSearch.js.map +1 -1
- package/dist/C_GlobalSearch2.js.map +1 -1
- package/dist/C_Guide.cjs +1 -1
- package/dist/C_Guide.js +1 -1
- package/dist/C_Guide.js.map +1 -1
- package/dist/C_Guide2.js +1 -1
- package/dist/C_Guide2.js.map +1 -1
- package/dist/C_Icon.js.map +1 -1
- package/dist/C_Icon2.js +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/{C_ImageCropper-D3L2-J_J.css.map → C_ImageCropper-BqZpkZfU.css.map} +1 -1
- package/dist/{C_ImageCropper-DrmUlaLi.css.map → C_ImageCropper-CylwGuzS.css.map} +1 -1
- package/dist/C_ImageCropper.cjs +1 -1
- package/dist/C_ImageCropper.css +10 -10
- package/dist/C_ImageCropper.js +1 -1
- package/dist/C_ImageCropper.js.map +1 -1
- package/dist/C_ImageCropper2.js +1 -1
- package/dist/C_ImageCropper2.js.map +1 -1
- package/dist/C_Language.cjs +1 -1
- package/dist/C_Language.js +1 -1
- package/dist/C_Language.js.map +1 -1
- package/dist/C_Language2.js +1 -1
- package/dist/C_Language2.js.map +1 -1
- package/dist/{C_Login-Cst_W1XC.css.map → C_Login-BkdnkBKX.css.map} +1 -1
- package/dist/{C_Login-DWZ_6K1x.css.map → C_Login-VkMM6OJ2.css.map} +1 -1
- package/dist/C_Login.cjs +1 -1
- package/dist/C_Login.css +72 -72
- package/dist/C_Login.js +1 -1
- package/dist/C_Login.js.map +1 -1
- package/dist/C_Login2.js +1 -1
- package/dist/C_Login2.js.map +1 -1
- package/dist/{C_Map-BCJmDnJT.css.map → C_Map-DNnBcY70.css.map} +1 -1
- package/dist/{C_Map-WUMXSAfy.css.map → C_Map-LEXIx6zM.css.map} +1 -1
- package/dist/C_Map.css +4 -4
- package/dist/C_Map.js.map +1 -1
- package/dist/C_Map2.js +1 -1
- package/dist/C_Map2.js.map +1 -1
- package/dist/{C_Markdown-7J0uPEuk.css.map → C_Markdown-DwmI0_0Q.css.map} +1 -1
- package/dist/{C_Markdown-C7Lg0_9z.css.map → C_Markdown-k0794RW0.css.map} +1 -1
- package/dist/C_Markdown.css +33 -33
- package/dist/C_Markdown.js.map +1 -1
- package/dist/C_Markdown2.js +1 -1
- package/dist/C_Markdown2.js.map +1 -1
- package/dist/C_Menu.js.map +1 -1
- package/dist/C_Menu2.js +1 -1
- package/dist/C_Menu2.js.map +1 -1
- package/dist/C_NotificationCenter.cjs +1 -1
- package/dist/C_NotificationCenter.js +1 -1
- package/dist/C_NotificationCenter.js.map +1 -1
- package/dist/C_NotificationCenter2.js +1 -1
- package/dist/C_NotificationCenter2.js.map +1 -1
- package/dist/C_OrgChart.js.map +1 -1
- package/dist/C_OrgChart2.js +1 -1
- package/dist/C_OrgChart2.js.map +1 -1
- package/dist/C_Progress.js.map +1 -1
- package/dist/C_Progress2.js +1 -1
- package/dist/C_Progress2.js.map +1 -1
- package/dist/{C_QRCode-DMxSyogU.css.map → C_QRCode-CFNTda_1.css.map} +1 -1
- package/dist/{C_QRCode-G7fiAkm4.css.map → C_QRCode-CmWr9lK-.css.map} +1 -1
- package/dist/C_QRCode.css +9 -9
- package/dist/C_QRCode.js.map +1 -1
- package/dist/C_QRCode2.js +1 -1
- package/dist/C_QRCode2.js.map +1 -1
- package/dist/{C_Signature-BJMvVPWT.css.map → C_Signature-BDx4ctsE.css.map} +1 -1
- package/dist/{C_Signature-BJUHx2BF.css.map → C_Signature-Bz_uNbwv.css.map} +1 -1
- package/dist/C_Signature.cjs +1 -1
- package/dist/C_Signature.css +15 -15
- package/dist/C_Signature.js +1 -1
- package/dist/C_Signature.js.map +1 -1
- package/dist/C_Signature2.js +1 -1
- package/dist/C_Signature2.js.map +1 -1
- package/dist/C_Skeleton.js.map +1 -1
- package/dist/C_Skeleton2.js +1 -1
- package/dist/C_Skeleton2.js.map +1 -1
- package/dist/{C_SplitPane-Br2eK8IG.css.map → C_SplitPane-BOwr1C7K.css.map} +1 -1
- package/dist/{C_SplitPane-DuyzUhKB.css.map → C_SplitPane-N-a_D-7F.css.map} +1 -1
- package/dist/C_SplitPane.cjs +1 -1
- package/dist/C_SplitPane.css +31 -31
- package/dist/C_SplitPane.js +1 -1
- package/dist/C_SplitPane.js.map +1 -1
- package/dist/C_SplitPane2.js +1 -1
- package/dist/C_SplitPane2.js.map +1 -1
- package/dist/C_Steps-Bk1krgiR.css.map +1 -0
- package/dist/C_Steps-Dn2CMpy1.css.map +1 -0
- package/dist/C_Steps.css +38 -38
- package/dist/C_Steps.js.map +1 -1
- package/dist/C_Steps2.js +1 -1
- package/dist/C_Steps2.js.map +1 -1
- package/dist/C_Table.cjs +1 -1
- package/dist/C_Table.js +1 -1
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +2 -2
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-BsutyC3U.css.map → C_TagsView-DX3LecK1.css.map} +1 -1
- package/dist/{C_TagsView-Crm7yWg9.css.map → C_TagsView-DqOTa8bL.css.map} +1 -1
- package/dist/C_TagsView.cjs +1 -1
- package/dist/C_TagsView.css +36 -36
- package/dist/C_TagsView.js +1 -1
- package/dist/C_TagsView.js.map +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_TagsView2.js.map +1 -1
- package/dist/C_Theme.cjs +1 -1
- package/dist/C_Theme.js +1 -1
- package/dist/C_Theme.js.map +1 -1
- package/dist/C_Theme2.js +1 -1
- package/dist/C_Theme2.js.map +1 -1
- package/dist/C_Time-BzyQVvTS.css.map +1 -0
- package/dist/C_Time-DmpKLQHc.css.map +1 -0
- package/dist/C_Time.css +5 -5
- package/dist/C_Time.js.map +1 -1
- package/dist/C_Time2.js +1 -1
- package/dist/C_Time2.js.map +1 -1
- package/dist/{C_Timeline-DG70WtJP.css.map → C_Timeline-BKkimrZx.css.map} +1 -1
- package/dist/{C_Timeline-Dzxmmdjg.css.map → C_Timeline-DTuSCX6p.css.map} +1 -1
- package/dist/C_Timeline.cjs +1 -1
- package/dist/C_Timeline.css +45 -45
- package/dist/C_Timeline.js +1 -1
- package/dist/C_Timeline.js.map +1 -1
- package/dist/C_Timeline2.js +1 -1
- package/dist/C_Timeline2.js.map +1 -1
- package/dist/{C_Transfer-CCEqnC-v.css.map → C_Transfer-BOB6OBqS.css.map} +1 -1
- package/dist/{C_Transfer-CStPm4NP.css.map → C_Transfer-Dpq7ezWC.css.map} +1 -1
- package/dist/C_Transfer.cjs +1 -1
- package/dist/C_Transfer.css +31 -31
- package/dist/C_Transfer.js +1 -1
- package/dist/C_Transfer.js.map +1 -1
- package/dist/C_Transfer2.js +1 -1
- package/dist/C_Transfer2.js.map +1 -1
- package/dist/{C_Tree-B-Le4hjQ.css.map → C_Tree-D98nX9qT.css.map} +1 -1
- package/dist/{C_Tree-DnGc_MPb.css.map → C_Tree-ulfm7b-P.css.map} +1 -1
- package/dist/C_Tree.cjs +1 -1
- package/dist/C_Tree.css +33 -33
- package/dist/C_Tree.js +1 -1
- package/dist/C_Tree.js.map +1 -1
- package/dist/C_Tree2.js +1 -1
- package/dist/C_Tree2.js.map +1 -1
- package/dist/{C_Upload-CFAxVGVz.css.map → C_Upload-BR9fg5r4.css.map} +1 -1
- package/dist/{C_Upload-D8_QeSV0.css.map → C_Upload-CPqf74Ea.css.map} +1 -1
- package/dist/C_Upload.cjs +1 -1
- package/dist/C_Upload.css +4 -4
- package/dist/C_Upload.js +1 -1
- package/dist/C_Upload.js.map +1 -1
- package/dist/C_Upload2.js +2 -2
- package/dist/C_Upload2.js.map +1 -1
- package/dist/{C_VideoPlayer-Cdgv4Zq0.css.map → C_VideoPlayer-4J96tKfK.css.map} +1 -1
- package/dist/{C_VideoPlayer-rm0MODUv.css.map → C_VideoPlayer-D35seHkm.css.map} +1 -1
- package/dist/C_VideoPlayer.css +13 -13
- package/dist/C_VideoPlayer.js.map +1 -1
- package/dist/C_VideoPlayer2.js +3 -3
- package/dist/C_VideoPlayer2.js.map +1 -1
- package/dist/{C_VtableGantt-BpY-Rng3.css.map → C_VtableGantt-C2lxFmWg.css.map} +1 -1
- package/dist/{C_VtableGantt-DB87-jdS.css.map → C_VtableGantt-Dwnkw_WL.css.map} +1 -1
- package/dist/C_VtableGantt.cjs +1 -1
- package/dist/C_VtableGantt.css +15 -15
- package/dist/C_VtableGantt.js +1 -1
- package/dist/C_VtableGantt.js.map +1 -1
- package/dist/C_VtableGantt2.js +1 -1
- package/dist/C_VtableGantt2.js.map +1 -1
- package/dist/C_WaterFall.js.map +1 -1
- package/dist/C_WaterFall2.js +1 -1
- package/dist/C_WaterFall2.js.map +1 -1
- package/dist/{C_WorkFlow-7F6op6qN.css.map → C_WorkFlow-2hJfvvTK.css.map} +1 -1
- package/dist/{C_WorkFlow-Cy3HWA6A.css.map → C_WorkFlow-DHoNjl8-.css.map} +1 -1
- package/dist/C_WorkFlow.cjs +1 -1
- package/dist/C_WorkFlow.css +108 -108
- package/dist/C_WorkFlow.js +1 -1
- package/dist/C_WorkFlow.js.map +1 -1
- package/dist/C_WorkFlow2.js +1 -1
- package/dist/C_WorkFlow2.js.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants2.d.ts +4 -4
- package/dist/constants3.d.ts +2 -2
- package/dist/constants4.d.ts +6 -6
- package/dist/constants5.d.ts +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +2 -2
- package/dist/index10.vue.d.ts +1 -1
- package/dist/index12.vue.d.ts +2 -2
- package/dist/index13.vue.d.ts +3 -3
- package/dist/index14.vue.d.ts +3 -3
- package/dist/index15.vue.d.ts +7 -7
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index18.vue.d.ts +5 -5
- package/dist/index2.vue.d.ts +2 -2
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.ts +3 -3
- package/dist/index22.vue.d.ts +1 -1
- package/dist/index26.vue.d.ts +4 -4
- package/dist/index27.vue.d.ts +2 -2
- package/dist/index28.vue.d.ts +3 -3
- package/dist/index4.vue.d.ts +7 -7
- package/dist/index6.vue.d.ts +3 -3
- package/dist/index8.vue.d.ts +4 -4
- package/dist/menuAdapter.js.map +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +1483 -1483
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.ts +3 -3
- package/dist/useCropperCore.d.ts +5 -5
- package/dist/useDraggableLayout.d.ts +5 -5
- package/dist/useDynamicFormState.d.ts +21 -21
- package/dist/useEdgeInteraction.d.ts +3 -3
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.ts +3 -3
- package/dist/useModalEdit.d.ts +1 -1
- package/dist/useQRCode.d.ts +5 -5
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +5 -5
- package/dist/useSplitResize.d.ts +4 -4
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +3 -3
- package/dist/useWorkflowValidation.d.ts +2 -2
- package/package.json +5 -5
- package/dist/C_ActionBar-jZPsiXtT.css.map +0 -1
- package/dist/C_ActionBar-nnfbZCea.css.map +0 -1
- package/dist/C_Code-DPZlNSxL.css.map +0 -1
- package/dist/C_Code-avZjAnHD.css.map +0 -1
- package/dist/C_Editor-C49qURgb.css.map +0 -1
- package/dist/C_Editor-DuxBD9Qg.css.map +0 -1
- package/dist/C_FullCalendar-1U4VlG7X.css.map +0 -1
- package/dist/C_FullCalendar-DLUdCtqf.css.map +0 -1
- package/dist/C_Steps-BHYNJI1l.css.map +0 -1
- package/dist/C_Steps-DY7vl-4I.css.map +0 -1
- package/dist/C_Time-Bd_e1YDN.css.map +0 -1
- package/dist/C_Time-CKb_fwdm.css.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_CollapsePanel.js","names":["variant","bordered","expandIconPosition","items","$slots"],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_CollapsePanel.js","names":[],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 折叠面板组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-collapse-panel\"\n :class=\"[\n `c-collapse-panel--${variant}`,\n {\n 'c-collapse-panel--bordered': bordered,\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\n },\n ]\"\n >\n <div\n v-for=\"item in items\"\n :key=\"item.key\"\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\n class=\"collapse-item\"\n :class=\"{\n 'collapse-item--active': isExpanded(item.key),\n 'collapse-item--disabled': item.disabled,\n }\"\n >\n <!-- 面板头部 -->\n <div\n class=\"collapse-item__header\"\n role=\"button\"\n :aria-expanded=\"isExpanded(item.key)\"\n :aria-controls=\"`collapse-content-${item.key}`\"\n :aria-disabled=\"item.disabled\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"!item.disabled && toggle(item.key)\"\n @keydown=\"handleKeyDown($event, item.key)\"\n >\n <!-- 展开图标 -->\n <span\n class=\"collapse-item__arrow\"\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\n >\n <C_Icon\n name=\"mdi:chevron-right\"\n :size=\"16\"\n color=\"currentColor\"\n />\n </span>\n\n <!-- 标题区域 -->\n <div class=\"collapse-item__title-area\">\n <slot\n :name=\"`header-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n >\n <div class=\"collapse-item__title-group\">\n <C_Icon\n v-if=\"item.icon\"\n :name=\"item.icon\"\n :size=\"18\"\n color=\"currentColor\"\n class=\"collapse-item__icon\"\n />\n <span class=\"collapse-item__title\">{{ item.title }}</span>\n <span\n v-if=\"item.subtitle\"\n class=\"collapse-item__subtitle\"\n >\n {{ item.subtitle }}\n </span>\n </div>\n </slot>\n </div>\n\n <!-- 头部右侧操作区 -->\n <div\n v-if=\"$slots[`extra-${item.key}`]\"\n class=\"collapse-item__extra\"\n @click.stop\n >\n <slot\n :name=\"`extra-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n />\n </div>\n </div>\n\n <!-- 面板内容 -->\n <Transition\n name=\"collapse-slide\"\n @enter=\"onEnter\"\n @after-enter=\"onAfterEnter\"\n @leave=\"onLeave\"\n @after-leave=\"onAfterLeave\"\n >\n <div\n v-show=\"isExpanded(item.key)\"\n :id=\"`collapse-content-${item.key}`\"\n class=\"collapse-item__content-wrapper\"\n role=\"region\"\n :aria-labelledby=\"`collapse-header-${item.key}`\"\n >\n <div\n v-if=\"shouldRender(item)\"\n class=\"collapse-item__content\"\n >\n <slot\n :name=\"`panel-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n >\n <component\n :is=\"item.content\"\n v-if=\"item.content && typeof item.content !== 'string'\"\n />\n <template v-else-if=\"item.content\">{{ item.content }}</template>\n </slot>\n </div>\n </div>\n </Transition>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, toRef } from 'vue'\n import C_Icon from '../C_Icon/index.vue'\n import { useCollapsePanel } from './composables/useCollapsePanel'\n import type {\n CollapsePanelExpose,\n CollapsePanelItem,\n CollapsePanelVariant,\n ExpandIconPosition,\n } from './types'\n\n defineOptions({ name: 'C_CollapsePanel' })\n\n interface Props {\n /** 面板项配置数组 */\n items: CollapsePanelItem[]\n /** 当前激活面板的 key 数组(v-model) */\n activeKeys?: string[]\n /** 默认展开的面板 key 数组 */\n defaultActiveKeys?: string[]\n /** 是否手风琴模式 */\n accordion?: boolean\n /** 面板样式变体 */\n variant?: CollapsePanelVariant\n /** 展开图标位置 */\n expandIconPosition?: ExpandIconPosition\n /** 是否显示边框 */\n bordered?: boolean\n /** 展开状态 localStorage 持久化 key */\n persistKey?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n activeKeys: undefined,\n defaultActiveKeys: () => [],\n accordion: false,\n variant: 'default',\n expandIconPosition: 'left',\n bordered: true,\n persistKey: undefined,\n })\n\n const emit = defineEmits<{\n 'update:activeKeys': [keys: string[]]\n expand: [key: string]\n collapse: [key: string]\n change: [activeKeys: string[]]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\n\n const setPanelRef = (key: string, el: HTMLElement | null) => {\n if (el) {\n panelRefs.value.set(key, el)\n } else {\n panelRefs.value.delete(key)\n }\n }\n\n const {\n isExpanded,\n shouldRender,\n toggle,\n expandAll,\n collapseAll,\n getActiveKeys,\n handleKeyDown,\n } = useCollapsePanel({\n items: toRef(props, 'items'),\n activeKeys: toRef(props, 'activeKeys'),\n defaultActiveKeys: props.defaultActiveKeys,\n accordion: toRef(props, 'accordion'),\n persistKey: toRef(props, 'persistKey'),\n onChange: keys => {\n emit('update:activeKeys', keys)\n emit('change', keys)\n },\n onExpand: key => emit('expand', key),\n onCollapse: key => emit('collapse', key),\n })\n\n /* ─── 展开/折叠动画 ──────────────────────────── */\n const onEnter = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = '0'\n element.style.overflow = 'hidden'\n /* 强制 reflow */\n void element.offsetHeight\n element.style.height = `${element.scrollHeight}px`\n }\n\n const onAfterEnter = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = ''\n element.style.overflow = ''\n }\n\n const onLeave = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = `${element.scrollHeight}px`\n element.style.overflow = 'hidden'\n void element.offsetHeight\n element.style.height = '0'\n }\n\n const onAfterLeave = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = ''\n element.style.overflow = ''\n }\n\n /* ─── 滚动到指定面板 ─────────────────────────── */\n const scrollToPanel = (key: string) => {\n const el = panelRefs.value.get(key)\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\n }\n }\n\n /* ─── 暴露方法 ──────────────────────────────── */\n defineExpose<CollapsePanelExpose>({\n expandAll,\n collapseAll,\n toggle,\n getActiveKeys,\n scrollToPanel,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
package/dist/C_CollapsePanel2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{Fragment as n,Transition as r,computed as i,createBlock as a,createCommentVNode as o,createElementBlock as s,createElementVNode as c,createTextVNode as l,createVNode as u,defineComponent as d,normalizeClass as f,openBlock as p,ref as m,renderList as h,renderSlot as g,resolveDynamicComponent as _,toDisplayString as v,toRef as y,unref as b,vShow as x,watch as S,withCtx as C,withDirectives as w,withModifiers as T}from"vue";function E(e){let{items:t,activeKeys:n,defaultActiveKeys:r,accordion:a,persistKey:o,onChange:s,onExpand:c,onCollapse:l}=e,u=()=>{if(!o.value)return null;try{let e=localStorage.getItem(`collapse-panel:${o.value}`);return e?JSON.parse(e):null}catch{return null}},d=e=>{if(o.value)try{localStorage.setItem(`collapse-panel:${o.value}`,JSON.stringify(e))}catch{}},f=m(n.value===void 0?u()||[...r]:[...n.value]),p=m(new Set(f.value)),h=i({get:()=>n.value===void 0?f.value:n.value,set:e=>{f.value=e}}),g=e=>h.value.includes(e),_=e=>{let t=g(e.key);return e.destroyOnCollapse?t:e.lazy?p.value.has(e.key):!0},v=e=>{h.value=e,s?.(e),d(e)},y=e=>{let n=t.value.find(t=>t.key===e);if(!(!n||n.disabled))if(g(e))v(h.value.filter(t=>t!==e)),l?.(e);else{if(p.value.add(e),a.value){let t=h.value;v([e]),t.forEach(t=>{t!==e&&l?.(t)})}else v([...h.value,e]);c?.(e)}};return S(()=>n.value,e=>{e!==void 0&&(f.value=[...e],e.forEach(e=>p.value.add(e)),d(e))}),{currentKeys:h,renderedOnce:p,isExpanded:g,shouldRender:_,toggle:y,expandAll:()=>{if(a.value)return;let e=t.value.filter(e=>!e.disabled).map(e=>e.key);e.forEach(e=>p.value.add(e)),v(e)},collapseAll:()=>{v([])},getActiveKeys:()=>[...h.value],handleKeyDown:(e,t)=>{[`Enter`,` `].includes(e.key)&&(e.preventDefault(),y(t))}}}const D=[`aria-expanded`,`aria-controls`,`aria-disabled`,`tabindex`,`onClick`,`onKeydown`],O={class:`collapse-item__title-area`},k={class:`collapse-item__title-group`},A={class:`collapse-item__title`},j={key:1,class:`collapse-item__subtitle`},M=[`id`,`aria-labelledby`],N={key:0,class:`collapse-item__content`};var P=t(d({name:`C_CollapsePanel`,__name:`index`,props:{items:{},activeKeys:{default:void 0},defaultActiveKeys:{default:()=>[]},accordion:{type:Boolean,default:!1},variant:{default:`default`},expandIconPosition:{default:`left`},bordered:{type:Boolean,default:!0},persistKey:{default:void 0}},emits:[`update:activeKeys`,`expand`,`collapse`,`change`],setup(t,{expose:i,emit:d}){let S=t,P=d,F=m(null),I=m(new Map),L=(e,t)=>{t?I.value.set(e,t):I.value.delete(e)},{isExpanded:R,shouldRender:z,toggle:B,expandAll:V,collapseAll:H,getActiveKeys:U,handleKeyDown:W}=E({items:y(S,`items`),activeKeys:y(S,`activeKeys`),defaultActiveKeys:S.defaultActiveKeys,accordion:y(S,`accordion`),persistKey:y(S,`persistKey`),onChange:e=>{P(`update:activeKeys`,e),P(`change`,e)},onExpand:e=>P(`expand`,e),onCollapse:e=>P(`collapse`,e)}),G=e=>{let t=e;t.style.height=`0`,t.style.overflow=`hidden`,t.offsetHeight,t.style.height=`${t.scrollHeight}px`},K=e=>{let t=e;t.style.height=``,t.style.overflow=``},q=e=>{let t=e;t.style.height=`${t.scrollHeight}px`,t.style.overflow=`hidden`,t.offsetHeight,t.style.height=`0`},J=e=>{let t=e;t.style.height=``,t.style.overflow=``};return i({expandAll:V,collapseAll:H,toggle:B,getActiveKeys:U,scrollToPanel:e=>{let t=I.value.get(e);t&&t.scrollIntoView({behavior:`smooth`,block:`start`})}}),(t,i)=>(p(),s(`div`,{ref_key:`containerRef`,ref:F,class:f([`c-collapse-panel`,[`c-collapse-panel--${t.variant}`,{"c-collapse-panel--bordered":t.bordered,"c-collapse-panel--icon-right":t.expandIconPosition===`right`}]])},[(p(!0),s(n,null,h(t.items,d=>(p(),s(`div`,{key:d.key,ref_for:!0,ref:e=>L(d.key,e),class:f([`collapse-item`,{"collapse-item--active":b(R)(d.key),"collapse-item--disabled":d.disabled}])},[o(` 面板头部 `),c(`div`,{class:`collapse-item__header`,role:`button`,"aria-expanded":b(R)(d.key),"aria-controls":`collapse-content-${d.key}`,"aria-disabled":d.disabled,tabindex:d.disabled?-1:0,onClick:e=>!d.disabled&&b(B)(d.key),onKeydown:e=>b(W)(e,d.key)},[o(` 展开图标 `),c(`span`,{class:f([`collapse-item__arrow`,{"collapse-item__arrow--expanded":b(R)(d.key)}])},[u(e,{name:`mdi:chevron-right`,size:16,color:`currentColor`})],2),o(` 标题区域 `),c(`div`,O,[g(t.$slots,`header-${d.key}`,{item:d,expanded:b(R)(d.key)},()=>[c(`div`,k,[d.icon?(p(),a(e,{key:0,name:d.icon,size:18,color:`currentColor`,class:`collapse-item__icon`},null,8,[`name`])):o(`v-if`,!0),c(`span`,A,v(d.title),1),d.subtitle?(p(),s(`span`,j,v(d.subtitle),1)):o(`v-if`,!0)])],!0)]),o(` 头部右侧操作区 `),t.$slots[`extra-${d.key}`]?(p(),s(`div`,{key:0,class:`collapse-item__extra`,onClick:i[0]||=T(()=>{},[`stop`])},[g(t.$slots,`extra-${d.key}`,{item:d,expanded:b(R)(d.key)},void 0,!0)])):o(`v-if`,!0)],40,D),o(` 面板内容 `),u(r,{name:`collapse-slide`,onEnter:G,onAfterEnter:K,onLeave:q,onAfterLeave:J,persisted:``},{default:C(()=>[w(c(`div`,{id:`collapse-content-${d.key}`,class:`collapse-item__content-wrapper`,role:`region`,"aria-labelledby":`collapse-header-${d.key}`},[b(z)(d)?(p(),s(`div`,N,[g(t.$slots,`panel-${d.key}`,{item:d,expanded:b(R)(d.key)},()=>[d.content&&typeof d.content!=`string`?(p(),a(_(d.content),{key:0})):d.content?(p(),s(n,{key:1},[l(v(d.content),1)],64)):o(`v-if`,!0)],!0)])):o(`v-if`,!0)],8,M),[[x,b(R)(d.key)]])]),_:2},1024)],2))),128))],2))}}),[[`__scopeId`,`data-v-
|
|
1
|
+
import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{Fragment as n,Transition as r,computed as i,createBlock as a,createCommentVNode as o,createElementBlock as s,createElementVNode as c,createTextVNode as l,createVNode as u,defineComponent as d,normalizeClass as f,openBlock as p,ref as m,renderList as h,renderSlot as g,resolveDynamicComponent as _,toDisplayString as v,toRef as y,unref as b,vShow as x,watch as S,withCtx as C,withDirectives as w,withModifiers as T}from"vue";function E(e){let{items:t,activeKeys:n,defaultActiveKeys:r,accordion:a,persistKey:o,onChange:s,onExpand:c,onCollapse:l}=e,u=()=>{if(!o.value)return null;try{let e=localStorage.getItem(`collapse-panel:${o.value}`);return e?JSON.parse(e):null}catch{return null}},d=e=>{if(o.value)try{localStorage.setItem(`collapse-panel:${o.value}`,JSON.stringify(e))}catch{}},f=m(n.value===void 0?u()||[...r]:[...n.value]),p=m(new Set(f.value)),h=i({get:()=>n.value===void 0?f.value:n.value,set:e=>{f.value=e}}),g=e=>h.value.includes(e),_=e=>{let t=g(e.key);return e.destroyOnCollapse?t:e.lazy?p.value.has(e.key):!0},v=e=>{h.value=e,s?.(e),d(e)},y=e=>{let n=t.value.find(t=>t.key===e);if(!(!n||n.disabled))if(g(e))v(h.value.filter(t=>t!==e)),l?.(e);else{if(p.value.add(e),a.value){let t=h.value;v([e]),t.forEach(t=>{t!==e&&l?.(t)})}else v([...h.value,e]);c?.(e)}};return S(()=>n.value,e=>{e!==void 0&&(f.value=[...e],e.forEach(e=>p.value.add(e)),d(e))}),{currentKeys:h,renderedOnce:p,isExpanded:g,shouldRender:_,toggle:y,expandAll:()=>{if(a.value)return;let e=t.value.filter(e=>!e.disabled).map(e=>e.key);e.forEach(e=>p.value.add(e)),v(e)},collapseAll:()=>{v([])},getActiveKeys:()=>[...h.value],handleKeyDown:(e,t)=>{[`Enter`,` `].includes(e.key)&&(e.preventDefault(),y(t))}}}const D=[`aria-expanded`,`aria-controls`,`aria-disabled`,`tabindex`,`onClick`,`onKeydown`],O={class:`collapse-item__title-area`},k={class:`collapse-item__title-group`},A={class:`collapse-item__title`},j={key:1,class:`collapse-item__subtitle`},M=[`id`,`aria-labelledby`],N={key:0,class:`collapse-item__content`};var P=t(d({name:`C_CollapsePanel`,__name:`index`,props:{items:{},activeKeys:{default:void 0},defaultActiveKeys:{default:()=>[]},accordion:{type:Boolean,default:!1},variant:{default:`default`},expandIconPosition:{default:`left`},bordered:{type:Boolean,default:!0},persistKey:{default:void 0}},emits:[`update:activeKeys`,`expand`,`collapse`,`change`],setup(t,{expose:i,emit:d}){let S=t,P=d,F=m(null),I=m(new Map),L=(e,t)=>{t?I.value.set(e,t):I.value.delete(e)},{isExpanded:R,shouldRender:z,toggle:B,expandAll:V,collapseAll:H,getActiveKeys:U,handleKeyDown:W}=E({items:y(S,`items`),activeKeys:y(S,`activeKeys`),defaultActiveKeys:S.defaultActiveKeys,accordion:y(S,`accordion`),persistKey:y(S,`persistKey`),onChange:e=>{P(`update:activeKeys`,e),P(`change`,e)},onExpand:e=>P(`expand`,e),onCollapse:e=>P(`collapse`,e)}),G=e=>{let t=e;t.style.height=`0`,t.style.overflow=`hidden`,t.offsetHeight,t.style.height=`${t.scrollHeight}px`},K=e=>{let t=e;t.style.height=``,t.style.overflow=``},q=e=>{let t=e;t.style.height=`${t.scrollHeight}px`,t.style.overflow=`hidden`,t.offsetHeight,t.style.height=`0`},J=e=>{let t=e;t.style.height=``,t.style.overflow=``};return i({expandAll:V,collapseAll:H,toggle:B,getActiveKeys:U,scrollToPanel:e=>{let t=I.value.get(e);t&&t.scrollIntoView({behavior:`smooth`,block:`start`})}}),(t,i)=>(p(),s(`div`,{ref_key:`containerRef`,ref:F,class:f([`c-collapse-panel`,[`c-collapse-panel--${t.variant}`,{"c-collapse-panel--bordered":t.bordered,"c-collapse-panel--icon-right":t.expandIconPosition===`right`}]])},[(p(!0),s(n,null,h(t.items,d=>(p(),s(`div`,{key:d.key,ref_for:!0,ref:e=>L(d.key,e),class:f([`collapse-item`,{"collapse-item--active":b(R)(d.key),"collapse-item--disabled":d.disabled}])},[o(` 面板头部 `),c(`div`,{class:`collapse-item__header`,role:`button`,"aria-expanded":b(R)(d.key),"aria-controls":`collapse-content-${d.key}`,"aria-disabled":d.disabled,tabindex:d.disabled?-1:0,onClick:e=>!d.disabled&&b(B)(d.key),onKeydown:e=>b(W)(e,d.key)},[o(` 展开图标 `),c(`span`,{class:f([`collapse-item__arrow`,{"collapse-item__arrow--expanded":b(R)(d.key)}])},[u(e,{name:`mdi:chevron-right`,size:16,color:`currentColor`})],2),o(` 标题区域 `),c(`div`,O,[g(t.$slots,`header-${d.key}`,{item:d,expanded:b(R)(d.key)},()=>[c(`div`,k,[d.icon?(p(),a(e,{key:0,name:d.icon,size:18,color:`currentColor`,class:`collapse-item__icon`},null,8,[`name`])):o(`v-if`,!0),c(`span`,A,v(d.title),1),d.subtitle?(p(),s(`span`,j,v(d.subtitle),1)):o(`v-if`,!0)])],!0)]),o(` 头部右侧操作区 `),t.$slots[`extra-${d.key}`]?(p(),s(`div`,{key:0,class:`collapse-item__extra`,onClick:i[0]||=T(()=>{},[`stop`])},[g(t.$slots,`extra-${d.key}`,{item:d,expanded:b(R)(d.key)},void 0,!0)])):o(`v-if`,!0)],40,D),o(` 面板内容 `),u(r,{name:`collapse-slide`,onEnter:G,onAfterEnter:K,onLeave:q,onAfterLeave:J,persisted:``},{default:C(()=>[w(c(`div`,{id:`collapse-content-${d.key}`,class:`collapse-item__content-wrapper`,role:`region`,"aria-labelledby":`collapse-header-${d.key}`},[b(z)(d)?(p(),s(`div`,N,[g(t.$slots,`panel-${d.key}`,{item:d,expanded:b(R)(d.key)},()=>[d.content&&typeof d.content!=`string`?(p(),a(_(d.content),{key:0})):d.content?(p(),s(n,{key:1},[l(v(d.content),1)],64)):o(`v-if`,!0)],!0)])):o(`v-if`,!0)],8,M),[[x,b(R)(d.key)]])]),_:2},1024)],2))),128))],2))}}),[[`__scopeId`,`data-v-4e11a983`]]);export{E as n,P as t};
|
|
2
2
|
//# sourceMappingURL=C_CollapsePanel2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_CollapsePanel2.js","names":["variant","bordered","expandIconPosition","items","$slots"],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon\r\n name=\"mdi:chevron-right\"\r\n :size=\"16\"\r\n color=\"currentColor\"\r\n />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span\r\n v-if=\"item.subtitle\"\r\n class=\"collapse-item__subtitle\"\r\n >\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div\r\n v-if=\"shouldRender(item)\"\r\n class=\"collapse-item__content\"\r\n >\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <component\r\n :is=\"item.content\"\r\n v-if=\"item.content && typeof item.content !== 'string'\"\r\n />\r\n <template v-else-if=\"item.content\">{{ item.content }}</template>\r\n </slot>\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRef } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import { useCollapsePanel } from './composables/useCollapsePanel'\r\n import type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_CollapsePanel' })\r\n\r\n interface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[]\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[]\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[]\r\n /** 是否手风琴模式 */\r\n accordion?: boolean\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition\r\n /** 是否显示边框 */\r\n bordered?: boolean\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: 'default',\r\n expandIconPosition: 'left',\r\n bordered: true,\r\n persistKey: undefined,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'update:activeKeys': [keys: string[]]\r\n expand: [key: string]\r\n collapse: [key: string]\r\n change: [activeKeys: string[]]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\r\n\r\n const setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el)\r\n } else {\r\n panelRefs.value.delete(key)\r\n }\r\n }\r\n\r\n const {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n } = useCollapsePanel({\r\n items: toRef(props, 'items'),\r\n activeKeys: toRef(props, 'activeKeys'),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, 'accordion'),\r\n persistKey: toRef(props, 'persistKey'),\r\n onChange: keys => {\r\n emit('update:activeKeys', keys)\r\n emit('change', keys)\r\n },\r\n onExpand: key => emit('expand', key),\r\n onCollapse: key => emit('collapse', key),\r\n })\r\n\r\n /* ─── 展开/折叠动画 ──────────────────────────── */\r\n const onEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = '0'\r\n element.style.overflow = 'hidden'\r\n /* 强制 reflow */\r\n void element.offsetHeight\r\n element.style.height = `${element.scrollHeight}px`\r\n }\r\n\r\n const onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n const onLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = `${element.scrollHeight}px`\r\n element.style.overflow = 'hidden'\r\n void element.offsetHeight\r\n element.style.height = '0'\r\n }\r\n\r\n const onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement\r\n element.style.height = ''\r\n element.style.overflow = ''\r\n }\r\n\r\n /* ─── 滚动到指定面板 ─────────────────────────── */\r\n const scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key)\r\n if (el) {\r\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\r\n }\r\n }\r\n\r\n /* ─── 暴露方法 ──────────────────────────────── */\r\n defineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_CollapsePanel2.js","names":[],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 折叠面板组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-collapse-panel\"\n :class=\"[\n `c-collapse-panel--${variant}`,\n {\n 'c-collapse-panel--bordered': bordered,\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\n },\n ]\"\n >\n <div\n v-for=\"item in items\"\n :key=\"item.key\"\n :ref=\"el => setPanelRef(item.key, el as HTMLElement)\"\n class=\"collapse-item\"\n :class=\"{\n 'collapse-item--active': isExpanded(item.key),\n 'collapse-item--disabled': item.disabled,\n }\"\n >\n <!-- 面板头部 -->\n <div\n class=\"collapse-item__header\"\n role=\"button\"\n :aria-expanded=\"isExpanded(item.key)\"\n :aria-controls=\"`collapse-content-${item.key}`\"\n :aria-disabled=\"item.disabled\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"!item.disabled && toggle(item.key)\"\n @keydown=\"handleKeyDown($event, item.key)\"\n >\n <!-- 展开图标 -->\n <span\n class=\"collapse-item__arrow\"\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\n >\n <C_Icon\n name=\"mdi:chevron-right\"\n :size=\"16\"\n color=\"currentColor\"\n />\n </span>\n\n <!-- 标题区域 -->\n <div class=\"collapse-item__title-area\">\n <slot\n :name=\"`header-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n >\n <div class=\"collapse-item__title-group\">\n <C_Icon\n v-if=\"item.icon\"\n :name=\"item.icon\"\n :size=\"18\"\n color=\"currentColor\"\n class=\"collapse-item__icon\"\n />\n <span class=\"collapse-item__title\">{{ item.title }}</span>\n <span\n v-if=\"item.subtitle\"\n class=\"collapse-item__subtitle\"\n >\n {{ item.subtitle }}\n </span>\n </div>\n </slot>\n </div>\n\n <!-- 头部右侧操作区 -->\n <div\n v-if=\"$slots[`extra-${item.key}`]\"\n class=\"collapse-item__extra\"\n @click.stop\n >\n <slot\n :name=\"`extra-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n />\n </div>\n </div>\n\n <!-- 面板内容 -->\n <Transition\n name=\"collapse-slide\"\n @enter=\"onEnter\"\n @after-enter=\"onAfterEnter\"\n @leave=\"onLeave\"\n @after-leave=\"onAfterLeave\"\n >\n <div\n v-show=\"isExpanded(item.key)\"\n :id=\"`collapse-content-${item.key}`\"\n class=\"collapse-item__content-wrapper\"\n role=\"region\"\n :aria-labelledby=\"`collapse-header-${item.key}`\"\n >\n <div\n v-if=\"shouldRender(item)\"\n class=\"collapse-item__content\"\n >\n <slot\n :name=\"`panel-${item.key}`\"\n :item=\"item\"\n :expanded=\"isExpanded(item.key)\"\n >\n <component\n :is=\"item.content\"\n v-if=\"item.content && typeof item.content !== 'string'\"\n />\n <template v-else-if=\"item.content\">{{ item.content }}</template>\n </slot>\n </div>\n </div>\n </Transition>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, toRef } from 'vue'\n import C_Icon from '../C_Icon/index.vue'\n import { useCollapsePanel } from './composables/useCollapsePanel'\n import type {\n CollapsePanelExpose,\n CollapsePanelItem,\n CollapsePanelVariant,\n ExpandIconPosition,\n } from './types'\n\n defineOptions({ name: 'C_CollapsePanel' })\n\n interface Props {\n /** 面板项配置数组 */\n items: CollapsePanelItem[]\n /** 当前激活面板的 key 数组(v-model) */\n activeKeys?: string[]\n /** 默认展开的面板 key 数组 */\n defaultActiveKeys?: string[]\n /** 是否手风琴模式 */\n accordion?: boolean\n /** 面板样式变体 */\n variant?: CollapsePanelVariant\n /** 展开图标位置 */\n expandIconPosition?: ExpandIconPosition\n /** 是否显示边框 */\n bordered?: boolean\n /** 展开状态 localStorage 持久化 key */\n persistKey?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n activeKeys: undefined,\n defaultActiveKeys: () => [],\n accordion: false,\n variant: 'default',\n expandIconPosition: 'left',\n bordered: true,\n persistKey: undefined,\n })\n\n const emit = defineEmits<{\n 'update:activeKeys': [keys: string[]]\n expand: [key: string]\n collapse: [key: string]\n change: [activeKeys: string[]]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n const panelRefs = ref<Map<string, HTMLElement>>(new Map())\n\n const setPanelRef = (key: string, el: HTMLElement | null) => {\n if (el) {\n panelRefs.value.set(key, el)\n } else {\n panelRefs.value.delete(key)\n }\n }\n\n const {\n isExpanded,\n shouldRender,\n toggle,\n expandAll,\n collapseAll,\n getActiveKeys,\n handleKeyDown,\n } = useCollapsePanel({\n items: toRef(props, 'items'),\n activeKeys: toRef(props, 'activeKeys'),\n defaultActiveKeys: props.defaultActiveKeys,\n accordion: toRef(props, 'accordion'),\n persistKey: toRef(props, 'persistKey'),\n onChange: keys => {\n emit('update:activeKeys', keys)\n emit('change', keys)\n },\n onExpand: key => emit('expand', key),\n onCollapse: key => emit('collapse', key),\n })\n\n /* ─── 展开/折叠动画 ──────────────────────────── */\n const onEnter = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = '0'\n element.style.overflow = 'hidden'\n /* 强制 reflow */\n void element.offsetHeight\n element.style.height = `${element.scrollHeight}px`\n }\n\n const onAfterEnter = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = ''\n element.style.overflow = ''\n }\n\n const onLeave = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = `${element.scrollHeight}px`\n element.style.overflow = 'hidden'\n void element.offsetHeight\n element.style.height = '0'\n }\n\n const onAfterLeave = (el: Element) => {\n const element = el as HTMLElement\n element.style.height = ''\n element.style.overflow = ''\n }\n\n /* ─── 滚动到指定面板 ─────────────────────────── */\n const scrollToPanel = (key: string) => {\n const el = panelRefs.value.get(key)\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'start' })\n }\n }\n\n /* ─── 暴露方法 ──────────────────────────────── */\n defineExpose<CollapsePanelExpose>({\n expandAll,\n collapseAll,\n toggle,\n getActiveKeys,\n scrollToPanel,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_ContextMenu-
|
|
1
|
+
{"version":3,"file":"C_ContextMenu-B3Cgz_wJ.css","names":[],"sources":["../src/components/C_ContextMenu/index.vue?vue&type=style&index=0&scoped=cdd4d8bb&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-context-menu[data-v-cdd4d8bb] {\n --ctx-bg: var(--card-color);\n --ctx-bg-blur: 12px;\n --ctx-border: var(--border-color);\n --ctx-radius: 10px;\n --ctx-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);\n --ctx-padding: 6px;\n --ctx-text-primary: var(--app-text-primary);\n --ctx-text-secondary: var(--text-color-3);\n --ctx-text-danger: #d03050;\n --ctx-text-disabled: var(--text-color-3);\n --ctx-item-height: 32px;\n --ctx-item-padding: 0 12px;\n --ctx-item-radius: 6px;\n --ctx-item-hover-bg: color-mix(in srgb, var(--primary-color) 8%, transparent);\n --ctx-item-active-bg: color-mix(in srgb, var(--primary-color) 14%, transparent);\n --ctx-icon-size: 16px;\n --ctx-icon-gap: 10px;\n --ctx-shortcut-color: var(--text-color-3);\n --ctx-divider-color: var(--border-color);\n --ctx-divider-margin: 4px 8px;\n position: fixed;\n padding: var(--ctx-padding);\n background: var(--ctx-bg);\n backdrop-filter: blur(var(--ctx-bg-blur));\n border: 1px solid var(--ctx-border);\n border-radius: var(--ctx-radius);\n box-shadow: var(--ctx-shadow);\n color: var(--ctx-text-primary);\n font-size: 13px;\n user-select: none;\n outline: none;\n}\n.c-context-menu__item[data-v-cdd4d8bb] {\n position: relative;\n display: flex;\n align-items: center;\n height: var(--ctx-item-height);\n padding: var(--ctx-item-padding);\n border-radius: var(--ctx-item-radius);\n cursor: pointer;\n transition: background 0.15s;\n white-space: nowrap;\n gap: var(--ctx-icon-gap);\n}\n.c-context-menu__item[data-v-cdd4d8bb]:hover {\n background: var(--ctx-item-hover-bg);\n}\n.c-context-menu__item[data-v-cdd4d8bb]:active {\n background: var(--ctx-item-active-bg);\n}\n.c-context-menu__item.is-disabled[data-v-cdd4d8bb] {\n color: var(--ctx-text-disabled);\n cursor: not-allowed;\n pointer-events: none;\n}\n.c-context-menu__item.is-danger[data-v-cdd4d8bb] {\n color: var(--ctx-text-danger);\n}\n.c-context-menu__item.is-danger[data-v-cdd4d8bb]:hover {\n background: color-mix(in srgb, #d03050 12%, transparent);\n}\n.c-context-menu__icon[data-v-cdd4d8bb] {\n flex-shrink: 0;\n width: var(--ctx-icon-size);\n height: var(--ctx-icon-size);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--ctx-icon-size);\n}\n.c-context-menu__label[data-v-cdd4d8bb] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.c-context-menu__shortcut[data-v-cdd4d8bb] {\n flex-shrink: 0;\n margin-left: 24px;\n font-size: 11px;\n color: var(--ctx-shortcut-color);\n font-family: \"JetBrains Mono\", \"Fira Code\", monospace;\n}\n.c-context-menu__arrow[data-v-cdd4d8bb] {\n flex-shrink: 0;\n margin-left: 8px;\n font-size: 12px;\n color: var(--ctx-text-secondary);\n transition: transform 0.15s;\n}\n.c-context-menu__divider[data-v-cdd4d8bb] {\n height: 1px;\n margin: var(--ctx-divider-margin);\n background: var(--ctx-divider-color);\n}\n.c-context-menu__submenu[data-v-cdd4d8bb] {\n position: absolute;\n top: -6px;\n}\n.c-context-menu__submenu.is-right[data-v-cdd4d8bb] {\n left: 100%;\n margin-left: 4px;\n}\n.c-context-menu__submenu.is-left[data-v-cdd4d8bb] {\n right: 100%;\n margin-right: 4px;\n}\n.c-context-menu-overlay[data-v-cdd4d8bb] {\n position: fixed;\n inset: 0;\n z-index: 9998;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_ContextMenu-
|
|
1
|
+
{"version":3,"file":"C_ContextMenu-u1LixF3_.css","names":[],"sources":["../src/components/C_ContextMenu/index.vue?vue&type=style&index=0&scoped=cdd4d8bb&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-context-menu[data-v-cdd4d8bb] {\n --ctx-bg: var(--card-color);\n --ctx-bg-blur: 12px;\n --ctx-border: var(--border-color);\n --ctx-radius: 10px;\n --ctx-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);\n --ctx-padding: 6px;\n --ctx-text-primary: var(--app-text-primary);\n --ctx-text-secondary: var(--text-color-3);\n --ctx-text-danger: #d03050;\n --ctx-text-disabled: var(--text-color-3);\n --ctx-item-height: 32px;\n --ctx-item-padding: 0 12px;\n --ctx-item-radius: 6px;\n --ctx-item-hover-bg: color-mix(in srgb, var(--primary-color) 8%, transparent);\n --ctx-item-active-bg: color-mix(in srgb, var(--primary-color) 14%, transparent);\n --ctx-icon-size: 16px;\n --ctx-icon-gap: 10px;\n --ctx-shortcut-color: var(--text-color-3);\n --ctx-divider-color: var(--border-color);\n --ctx-divider-margin: 4px 8px;\n position: fixed;\n padding: var(--ctx-padding);\n background: var(--ctx-bg);\n backdrop-filter: blur(var(--ctx-bg-blur));\n border: 1px solid var(--ctx-border);\n border-radius: var(--ctx-radius);\n box-shadow: var(--ctx-shadow);\n color: var(--ctx-text-primary);\n font-size: 13px;\n user-select: none;\n outline: none;\n}\n.c-context-menu__item[data-v-cdd4d8bb] {\n position: relative;\n display: flex;\n align-items: center;\n height: var(--ctx-item-height);\n padding: var(--ctx-item-padding);\n border-radius: var(--ctx-item-radius);\n cursor: pointer;\n transition: background 0.15s;\n white-space: nowrap;\n gap: var(--ctx-icon-gap);\n}\n.c-context-menu__item[data-v-cdd4d8bb]:hover {\n background: var(--ctx-item-hover-bg);\n}\n.c-context-menu__item[data-v-cdd4d8bb]:active {\n background: var(--ctx-item-active-bg);\n}\n.c-context-menu__item.is-disabled[data-v-cdd4d8bb] {\n color: var(--ctx-text-disabled);\n cursor: not-allowed;\n pointer-events: none;\n}\n.c-context-menu__item.is-danger[data-v-cdd4d8bb] {\n color: var(--ctx-text-danger);\n}\n.c-context-menu__item.is-danger[data-v-cdd4d8bb]:hover {\n background: color-mix(in srgb, #d03050 12%, transparent);\n}\n.c-context-menu__icon[data-v-cdd4d8bb] {\n flex-shrink: 0;\n width: var(--ctx-icon-size);\n height: var(--ctx-icon-size);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--ctx-icon-size);\n}\n.c-context-menu__label[data-v-cdd4d8bb] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.c-context-menu__shortcut[data-v-cdd4d8bb] {\n flex-shrink: 0;\n margin-left: 24px;\n font-size: 11px;\n color: var(--ctx-shortcut-color);\n font-family: \"JetBrains Mono\", \"Fira Code\", monospace;\n}\n.c-context-menu__arrow[data-v-cdd4d8bb] {\n flex-shrink: 0;\n margin-left: 8px;\n font-size: 12px;\n color: var(--ctx-text-secondary);\n transition: transform 0.15s;\n}\n.c-context-menu__divider[data-v-cdd4d8bb] {\n height: 1px;\n margin: var(--ctx-divider-margin);\n background: var(--ctx-divider-color);\n}\n.c-context-menu__submenu[data-v-cdd4d8bb] {\n position: absolute;\n top: -6px;\n}\n.c-context-menu__submenu.is-right[data-v-cdd4d8bb] {\n left: 100%;\n margin-left: 4px;\n}\n.c-context-menu__submenu.is-left[data-v-cdd4d8bb] {\n right: 100%;\n margin-right: 4px;\n}\n.c-context-menu-overlay[data-v-cdd4d8bb] {\n position: fixed;\n inset: 0;\n z-index: 9998;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_ContextMenu.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./C_ContextMenu.js`);exports.C_ContextMenu=e.t,exports.DEFAULT_CONTEXT_MENU_PROPS=e.n;
|
package/dist/C_ContextMenu.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* unplugin-vue-components disabled */.c-context-menu[data-v-
|
|
1
|
+
/* unplugin-vue-components disabled */.c-context-menu[data-v-cdd4d8bb] {
|
|
2
2
|
--ctx-bg: var(--card-color);
|
|
3
3
|
--ctx-bg-blur: 12px;
|
|
4
4
|
--ctx-border: var(--border-color);
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
user-select: none;
|
|
32
32
|
outline: none;
|
|
33
33
|
}
|
|
34
|
-
.c-context-menu__item[data-v-
|
|
34
|
+
.c-context-menu__item[data-v-cdd4d8bb] {
|
|
35
35
|
position: relative;
|
|
36
36
|
display: flex;
|
|
37
37
|
align-items: center;
|
|
@@ -43,24 +43,24 @@
|
|
|
43
43
|
white-space: nowrap;
|
|
44
44
|
gap: var(--ctx-icon-gap);
|
|
45
45
|
}
|
|
46
|
-
.c-context-menu__item[data-v-
|
|
46
|
+
.c-context-menu__item[data-v-cdd4d8bb]:hover {
|
|
47
47
|
background: var(--ctx-item-hover-bg);
|
|
48
48
|
}
|
|
49
|
-
.c-context-menu__item[data-v-
|
|
49
|
+
.c-context-menu__item[data-v-cdd4d8bb]:active {
|
|
50
50
|
background: var(--ctx-item-active-bg);
|
|
51
51
|
}
|
|
52
|
-
.c-context-menu__item.is-disabled[data-v-
|
|
52
|
+
.c-context-menu__item.is-disabled[data-v-cdd4d8bb] {
|
|
53
53
|
color: var(--ctx-text-disabled);
|
|
54
54
|
cursor: not-allowed;
|
|
55
55
|
pointer-events: none;
|
|
56
56
|
}
|
|
57
|
-
.c-context-menu__item.is-danger[data-v-
|
|
57
|
+
.c-context-menu__item.is-danger[data-v-cdd4d8bb] {
|
|
58
58
|
color: var(--ctx-text-danger);
|
|
59
59
|
}
|
|
60
|
-
.c-context-menu__item.is-danger[data-v-
|
|
60
|
+
.c-context-menu__item.is-danger[data-v-cdd4d8bb]:hover {
|
|
61
61
|
background: color-mix(in srgb, #d03050 12%, transparent);
|
|
62
62
|
}
|
|
63
|
-
.c-context-menu__icon[data-v-
|
|
63
|
+
.c-context-menu__icon[data-v-cdd4d8bb] {
|
|
64
64
|
flex-shrink: 0;
|
|
65
65
|
width: var(--ctx-icon-size);
|
|
66
66
|
height: var(--ctx-icon-size);
|
|
@@ -69,47 +69,47 @@
|
|
|
69
69
|
justify-content: center;
|
|
70
70
|
font-size: var(--ctx-icon-size);
|
|
71
71
|
}
|
|
72
|
-
.c-context-menu__label[data-v-
|
|
72
|
+
.c-context-menu__label[data-v-cdd4d8bb] {
|
|
73
73
|
flex: 1;
|
|
74
74
|
min-width: 0;
|
|
75
75
|
overflow: hidden;
|
|
76
76
|
text-overflow: ellipsis;
|
|
77
77
|
}
|
|
78
|
-
.c-context-menu__shortcut[data-v-
|
|
78
|
+
.c-context-menu__shortcut[data-v-cdd4d8bb] {
|
|
79
79
|
flex-shrink: 0;
|
|
80
80
|
margin-left: 24px;
|
|
81
81
|
font-size: 11px;
|
|
82
82
|
color: var(--ctx-shortcut-color);
|
|
83
83
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
84
84
|
}
|
|
85
|
-
.c-context-menu__arrow[data-v-
|
|
85
|
+
.c-context-menu__arrow[data-v-cdd4d8bb] {
|
|
86
86
|
flex-shrink: 0;
|
|
87
87
|
margin-left: 8px;
|
|
88
88
|
font-size: 12px;
|
|
89
89
|
color: var(--ctx-text-secondary);
|
|
90
90
|
transition: transform 0.15s;
|
|
91
91
|
}
|
|
92
|
-
.c-context-menu__divider[data-v-
|
|
92
|
+
.c-context-menu__divider[data-v-cdd4d8bb] {
|
|
93
93
|
height: 1px;
|
|
94
94
|
margin: var(--ctx-divider-margin);
|
|
95
95
|
background: var(--ctx-divider-color);
|
|
96
96
|
}
|
|
97
|
-
.c-context-menu__submenu[data-v-
|
|
97
|
+
.c-context-menu__submenu[data-v-cdd4d8bb] {
|
|
98
98
|
position: absolute;
|
|
99
99
|
top: -6px;
|
|
100
100
|
}
|
|
101
|
-
.c-context-menu__submenu.is-right[data-v-
|
|
101
|
+
.c-context-menu__submenu.is-right[data-v-cdd4d8bb] {
|
|
102
102
|
left: 100%;
|
|
103
103
|
margin-left: 4px;
|
|
104
104
|
}
|
|
105
|
-
.c-context-menu__submenu.is-left[data-v-
|
|
105
|
+
.c-context-menu__submenu.is-left[data-v-cdd4d8bb] {
|
|
106
106
|
right: 100%;
|
|
107
107
|
margin-right: 4px;
|
|
108
108
|
}
|
|
109
|
-
.c-context-menu-overlay[data-v-
|
|
109
|
+
.c-context-menu-overlay[data-v-cdd4d8bb] {
|
|
110
110
|
position: fixed;
|
|
111
111
|
inset: 0;
|
|
112
112
|
z-index: 9998;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
/*# sourceMappingURL=C_ContextMenu-
|
|
115
|
+
/*# sourceMappingURL=C_ContextMenu-B3Cgz_wJ.css.map*/
|
package/dist/C_ContextMenu.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import{n as e,t}from"./C_ContextMenu2.js";export{t as C_ContextMenu,e as DEFAULT_CONTEXT_MENU_PROPS};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_ContextMenu.js","names":[],"sources":["../src/components/C_ContextMenu/types.ts","../src/components/C_ContextMenu/index.vue","../src/components/C_ContextMenu/index.vue","../src/components/C_ContextMenu/index.vue"],"sourcesContent":["/**\r\n * @Description: 右键菜单组件类型定义\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n */\r\n\r\n/** 菜单项 */\r\nexport interface ContextMenuItem {\r\n /** 唯一标识 */\r\n key: string\r\n /** 菜单文字 */\r\n label: string\r\n /** 图标(Iconify 图标名) */\r\n icon?: string\r\n /** 快捷键标注文字(仅展示,不绑定) */\r\n shortcut?: string\r\n /** 是否禁用 */\r\n disabled?: boolean\r\n /** 是否隐藏 */\r\n hidden?: boolean\r\n /** 分割线(此项渲染为分割线,label 被忽略) */\r\n divider?: boolean\r\n /** 子菜单(支持无限嵌套) */\r\n children?: ContextMenuItem[]\r\n /** 自定义样式类 */\r\n className?: string\r\n /** 危险操作(红色高亮) */\r\n danger?: boolean\r\n}\r\n\r\n/** 组件 Props */\r\nexport interface ContextMenuProps {\r\n /** 菜单项列表 */\r\n items: ContextMenuItem[]\r\n /** 菜单最小宽度 */\r\n minWidth?: number\r\n /** 菜单最大宽度 */\r\n maxWidth?: number\r\n /** 子菜单展开方向 */\r\n subMenuPlacement?: 'right' | 'left'\r\n /** 点击菜单项后是否自动关闭 */\r\n autoClose?: boolean\r\n /** 是否禁用整个菜单 */\r\n disabled?: boolean\r\n /** 自定义 z-index */\r\n zIndex?: number\r\n}\r\n\r\n/** 默认 Props */\r\nexport const DEFAULT_CONTEXT_MENU_PROPS = {\r\n minWidth: 180,\r\n maxWidth: 280,\r\n subMenuPlacement: 'right' as const,\r\n autoClose: true,\r\n disabled: false,\r\n zIndex: 9999,\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 右键菜单组件 — 声明式配置、快捷键标注、嵌套子菜单\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <!-- 遮罩层 -->\r\n <Teleport to=\"body\">\r\n <div\r\n v-if=\"visible\"\r\n class=\"c-context-menu-overlay\"\r\n :style=\"{ zIndex: props.zIndex - 1 }\"\r\n @click=\"close\"\r\n @contextmenu.prevent=\"close\"\r\n />\r\n\r\n <!-- 菜单面板 -->\r\n <div\r\n v-if=\"visible\"\r\n ref=\"menuRef\"\r\n class=\"c-context-menu\"\r\n :style=\"menuStyle\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n @keydown.escape=\"close\"\r\n >\r\n <template\r\n v-for=\"item in visibleItems\"\r\n :key=\"item.key\"\r\n >\r\n <!-- 分割线 -->\r\n <div\r\n v-if=\"item.divider\"\r\n class=\"c-context-menu__divider\"\r\n role=\"separator\"\r\n />\r\n\r\n <!-- 普通菜单项 -->\r\n <div\r\n v-else\r\n :class=\"[\r\n 'c-context-menu__item',\r\n {\r\n 'is-disabled': item.disabled,\r\n 'is-danger': item.danger,\r\n },\r\n ]\"\r\n role=\"menuitem\"\r\n :aria-disabled=\"item.disabled\"\r\n @click=\"handleItemClick(item)\"\r\n @mouseenter=\"handleMouseEnter(item)\"\r\n @mouseleave=\"handleMouseLeave\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"item.icon\"\r\n class=\"c-context-menu__icon\"\r\n >\r\n <C_Icon :name=\"item.icon\" />\r\n </span>\r\n\r\n <!-- 文本 -->\r\n <span class=\"c-context-menu__label\">{{ item.label }}</span>\r\n\r\n <!-- 快捷键 -->\r\n <span\r\n v-if=\"item.shortcut\"\r\n class=\"c-context-menu__shortcut\"\r\n >\r\n {{ item.shortcut }}\r\n </span>\r\n\r\n <!-- 子菜单箭头 -->\r\n <span\r\n v-if=\"item.children?.length\"\r\n class=\"c-context-menu__arrow\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" />\r\n </span>\r\n\r\n <!-- 子菜单(递归) -->\r\n <C_ContextMenu\r\n v-if=\"item.children?.length && activeSubKey === item.key\"\r\n :items=\"item.children\"\r\n :min-width=\"props.minWidth\"\r\n :max-width=\"props.maxWidth\"\r\n :sub-menu-placement=\"props.subMenuPlacement\"\r\n :auto-close=\"props.autoClose\"\r\n :z-index=\"props.zIndex + 1\"\r\n class=\"c-context-menu__submenu\"\r\n :class=\"`is-${props.subMenuPlacement}`\"\r\n :style=\"{ position: 'absolute' }\"\r\n @select=\"handleSubSelect\"\r\n />\r\n </div>\r\n </template>\r\n </div>\r\n </Teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, nextTick, ref } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_CONTEXT_MENU_PROPS,\r\n type ContextMenuItem,\r\n type ContextMenuProps,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_ContextMenu' })\r\n\r\n const props = withDefaults(defineProps<ContextMenuProps>(), {\r\n items: () => [],\r\n minWidth: DEFAULT_CONTEXT_MENU_PROPS.minWidth,\r\n maxWidth: DEFAULT_CONTEXT_MENU_PROPS.maxWidth,\r\n subMenuPlacement: DEFAULT_CONTEXT_MENU_PROPS.subMenuPlacement,\r\n autoClose: DEFAULT_CONTEXT_MENU_PROPS.autoClose,\r\n disabled: DEFAULT_CONTEXT_MENU_PROPS.disabled,\r\n zIndex: DEFAULT_CONTEXT_MENU_PROPS.zIndex,\r\n })\r\n\r\n const emit = defineEmits<{\r\n (e: 'select', item: ContextMenuItem): void\r\n (e: 'open', position: { x: number; y: number }): void\r\n (e: 'close'): void\r\n }>()\r\n\r\n // ===== 状态 =====\r\n const visible = ref(false)\r\n const position = ref({ x: 0, y: 0 })\r\n const menuRef = ref<HTMLElement>()\r\n const activeSubKey = ref<string | null>(null)\r\n\r\n let subTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n // ===== 可见项 =====\r\n const visibleItems = computed(() => props.items.filter(item => !item.hidden))\r\n\r\n // ===== 菜单定位样式 =====\r\n const menuStyle = computed(() => ({\r\n left: `${position.value.x}px`,\r\n top: `${position.value.y}px`,\r\n minWidth: `${props.minWidth}px`,\r\n maxWidth: `${props.maxWidth}px`,\r\n zIndex: props.zIndex,\r\n }))\r\n\r\n // ===== 边界校正 =====\r\n const adjustPosition = () => {\r\n nextTick(() => {\r\n const el = menuRef.value\r\n if (!el) return\r\n const rect = el.getBoundingClientRect()\r\n const { innerWidth, innerHeight } = window\r\n\r\n if (rect.right > innerWidth) {\r\n position.value.x = innerWidth - rect.width - 8\r\n }\r\n if (rect.bottom > innerHeight) {\r\n position.value.y = innerHeight - rect.height - 8\r\n }\r\n if (position.value.x < 0) position.value.x = 8\r\n if (position.value.y < 0) position.value.y = 8\r\n })\r\n }\r\n\r\n // ===== 打开/关闭 =====\r\n const open = (x: number, y: number) => {\r\n if (props.disabled) return\r\n position.value = { x, y }\r\n visible.value = true\r\n emit('open', { x, y })\r\n adjustPosition()\r\n\r\n // 聚焦以支持 Escape 关闭\r\n nextTick(() => menuRef.value?.focus())\r\n }\r\n\r\n const close = () => {\r\n visible.value = false\r\n activeSubKey.value = null\r\n emit('close')\r\n }\r\n\r\n // ===== 菜单项点击 =====\r\n const handleItemClick = (item: ContextMenuItem) => {\r\n if (item.disabled) return\r\n if (item.children?.length) return // 有子菜单不触发\r\n\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 子菜单悬停 =====\r\n const handleMouseEnter = (item: ContextMenuItem) => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n if (item.children?.length && !item.disabled) {\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = item.key\r\n }, 150)\r\n } else {\r\n activeSubKey.value = null\r\n }\r\n }\r\n\r\n const handleMouseLeave = () => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = null\r\n }, 300)\r\n }\r\n\r\n // ===== 子菜单选择向上冒泡 =====\r\n const handleSubSelect = (item: ContextMenuItem) => {\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 暴露 API =====\r\n defineExpose({\r\n /** 在指定坐标打开菜单 */\r\n open,\r\n /** 关闭菜单 */\r\n close,\r\n /** 当前是否可见 */\r\n visible: computed(() => visible.value),\r\n })\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 右键菜单组件 — 声明式配置、快捷键标注、嵌套子菜单\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <!-- 遮罩层 -->\r\n <Teleport to=\"body\">\r\n <div\r\n v-if=\"visible\"\r\n class=\"c-context-menu-overlay\"\r\n :style=\"{ zIndex: props.zIndex - 1 }\"\r\n @click=\"close\"\r\n @contextmenu.prevent=\"close\"\r\n />\r\n\r\n <!-- 菜单面板 -->\r\n <div\r\n v-if=\"visible\"\r\n ref=\"menuRef\"\r\n class=\"c-context-menu\"\r\n :style=\"menuStyle\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n @keydown.escape=\"close\"\r\n >\r\n <template\r\n v-for=\"item in visibleItems\"\r\n :key=\"item.key\"\r\n >\r\n <!-- 分割线 -->\r\n <div\r\n v-if=\"item.divider\"\r\n class=\"c-context-menu__divider\"\r\n role=\"separator\"\r\n />\r\n\r\n <!-- 普通菜单项 -->\r\n <div\r\n v-else\r\n :class=\"[\r\n 'c-context-menu__item',\r\n {\r\n 'is-disabled': item.disabled,\r\n 'is-danger': item.danger,\r\n },\r\n ]\"\r\n role=\"menuitem\"\r\n :aria-disabled=\"item.disabled\"\r\n @click=\"handleItemClick(item)\"\r\n @mouseenter=\"handleMouseEnter(item)\"\r\n @mouseleave=\"handleMouseLeave\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"item.icon\"\r\n class=\"c-context-menu__icon\"\r\n >\r\n <C_Icon :name=\"item.icon\" />\r\n </span>\r\n\r\n <!-- 文本 -->\r\n <span class=\"c-context-menu__label\">{{ item.label }}</span>\r\n\r\n <!-- 快捷键 -->\r\n <span\r\n v-if=\"item.shortcut\"\r\n class=\"c-context-menu__shortcut\"\r\n >\r\n {{ item.shortcut }}\r\n </span>\r\n\r\n <!-- 子菜单箭头 -->\r\n <span\r\n v-if=\"item.children?.length\"\r\n class=\"c-context-menu__arrow\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" />\r\n </span>\r\n\r\n <!-- 子菜单(递归) -->\r\n <C_ContextMenu\r\n v-if=\"item.children?.length && activeSubKey === item.key\"\r\n :items=\"item.children\"\r\n :min-width=\"props.minWidth\"\r\n :max-width=\"props.maxWidth\"\r\n :sub-menu-placement=\"props.subMenuPlacement\"\r\n :auto-close=\"props.autoClose\"\r\n :z-index=\"props.zIndex + 1\"\r\n class=\"c-context-menu__submenu\"\r\n :class=\"`is-${props.subMenuPlacement}`\"\r\n :style=\"{ position: 'absolute' }\"\r\n @select=\"handleSubSelect\"\r\n />\r\n </div>\r\n </template>\r\n </div>\r\n </Teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, nextTick, ref } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_CONTEXT_MENU_PROPS,\r\n type ContextMenuItem,\r\n type ContextMenuProps,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_ContextMenu' })\r\n\r\n const props = withDefaults(defineProps<ContextMenuProps>(), {\r\n items: () => [],\r\n minWidth: DEFAULT_CONTEXT_MENU_PROPS.minWidth,\r\n maxWidth: DEFAULT_CONTEXT_MENU_PROPS.maxWidth,\r\n subMenuPlacement: DEFAULT_CONTEXT_MENU_PROPS.subMenuPlacement,\r\n autoClose: DEFAULT_CONTEXT_MENU_PROPS.autoClose,\r\n disabled: DEFAULT_CONTEXT_MENU_PROPS.disabled,\r\n zIndex: DEFAULT_CONTEXT_MENU_PROPS.zIndex,\r\n })\r\n\r\n const emit = defineEmits<{\r\n (e: 'select', item: ContextMenuItem): void\r\n (e: 'open', position: { x: number; y: number }): void\r\n (e: 'close'): void\r\n }>()\r\n\r\n // ===== 状态 =====\r\n const visible = ref(false)\r\n const position = ref({ x: 0, y: 0 })\r\n const menuRef = ref<HTMLElement>()\r\n const activeSubKey = ref<string | null>(null)\r\n\r\n let subTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n // ===== 可见项 =====\r\n const visibleItems = computed(() => props.items.filter(item => !item.hidden))\r\n\r\n // ===== 菜单定位样式 =====\r\n const menuStyle = computed(() => ({\r\n left: `${position.value.x}px`,\r\n top: `${position.value.y}px`,\r\n minWidth: `${props.minWidth}px`,\r\n maxWidth: `${props.maxWidth}px`,\r\n zIndex: props.zIndex,\r\n }))\r\n\r\n // ===== 边界校正 =====\r\n const adjustPosition = () => {\r\n nextTick(() => {\r\n const el = menuRef.value\r\n if (!el) return\r\n const rect = el.getBoundingClientRect()\r\n const { innerWidth, innerHeight } = window\r\n\r\n if (rect.right > innerWidth) {\r\n position.value.x = innerWidth - rect.width - 8\r\n }\r\n if (rect.bottom > innerHeight) {\r\n position.value.y = innerHeight - rect.height - 8\r\n }\r\n if (position.value.x < 0) position.value.x = 8\r\n if (position.value.y < 0) position.value.y = 8\r\n })\r\n }\r\n\r\n // ===== 打开/关闭 =====\r\n const open = (x: number, y: number) => {\r\n if (props.disabled) return\r\n position.value = { x, y }\r\n visible.value = true\r\n emit('open', { x, y })\r\n adjustPosition()\r\n\r\n // 聚焦以支持 Escape 关闭\r\n nextTick(() => menuRef.value?.focus())\r\n }\r\n\r\n const close = () => {\r\n visible.value = false\r\n activeSubKey.value = null\r\n emit('close')\r\n }\r\n\r\n // ===== 菜单项点击 =====\r\n const handleItemClick = (item: ContextMenuItem) => {\r\n if (item.disabled) return\r\n if (item.children?.length) return // 有子菜单不触发\r\n\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 子菜单悬停 =====\r\n const handleMouseEnter = (item: ContextMenuItem) => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n if (item.children?.length && !item.disabled) {\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = item.key\r\n }, 150)\r\n } else {\r\n activeSubKey.value = null\r\n }\r\n }\r\n\r\n const handleMouseLeave = () => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = null\r\n }, 300)\r\n }\r\n\r\n // ===== 子菜单选择向上冒泡 =====\r\n const handleSubSelect = (item: ContextMenuItem) => {\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 暴露 API =====\r\n defineExpose({\r\n /** 在指定坐标打开菜单 */\r\n open,\r\n /** 关闭菜单 */\r\n close,\r\n /** 当前是否可见 */\r\n visible: computed(() => visible.value),\r\n })\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Description: 右键菜单组件 — 声明式配置、快捷键标注、嵌套子菜单\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <!-- 遮罩层 -->\r\n <Teleport to=\"body\">\r\n <div\r\n v-if=\"visible\"\r\n class=\"c-context-menu-overlay\"\r\n :style=\"{ zIndex: props.zIndex - 1 }\"\r\n @click=\"close\"\r\n @contextmenu.prevent=\"close\"\r\n />\r\n\r\n <!-- 菜单面板 -->\r\n <div\r\n v-if=\"visible\"\r\n ref=\"menuRef\"\r\n class=\"c-context-menu\"\r\n :style=\"menuStyle\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n @keydown.escape=\"close\"\r\n >\r\n <template\r\n v-for=\"item in visibleItems\"\r\n :key=\"item.key\"\r\n >\r\n <!-- 分割线 -->\r\n <div\r\n v-if=\"item.divider\"\r\n class=\"c-context-menu__divider\"\r\n role=\"separator\"\r\n />\r\n\r\n <!-- 普通菜单项 -->\r\n <div\r\n v-else\r\n :class=\"[\r\n 'c-context-menu__item',\r\n {\r\n 'is-disabled': item.disabled,\r\n 'is-danger': item.danger,\r\n },\r\n ]\"\r\n role=\"menuitem\"\r\n :aria-disabled=\"item.disabled\"\r\n @click=\"handleItemClick(item)\"\r\n @mouseenter=\"handleMouseEnter(item)\"\r\n @mouseleave=\"handleMouseLeave\"\r\n >\r\n <!-- 图标 -->\r\n <span\r\n v-if=\"item.icon\"\r\n class=\"c-context-menu__icon\"\r\n >\r\n <C_Icon :name=\"item.icon\" />\r\n </span>\r\n\r\n <!-- 文本 -->\r\n <span class=\"c-context-menu__label\">{{ item.label }}</span>\r\n\r\n <!-- 快捷键 -->\r\n <span\r\n v-if=\"item.shortcut\"\r\n class=\"c-context-menu__shortcut\"\r\n >\r\n {{ item.shortcut }}\r\n </span>\r\n\r\n <!-- 子菜单箭头 -->\r\n <span\r\n v-if=\"item.children?.length\"\r\n class=\"c-context-menu__arrow\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" />\r\n </span>\r\n\r\n <!-- 子菜单(递归) -->\r\n <C_ContextMenu\r\n v-if=\"item.children?.length && activeSubKey === item.key\"\r\n :items=\"item.children\"\r\n :min-width=\"props.minWidth\"\r\n :max-width=\"props.maxWidth\"\r\n :sub-menu-placement=\"props.subMenuPlacement\"\r\n :auto-close=\"props.autoClose\"\r\n :z-index=\"props.zIndex + 1\"\r\n class=\"c-context-menu__submenu\"\r\n :class=\"`is-${props.subMenuPlacement}`\"\r\n :style=\"{ position: 'absolute' }\"\r\n @select=\"handleSubSelect\"\r\n />\r\n </div>\r\n </template>\r\n </div>\r\n </Teleport>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, nextTick, ref } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_CONTEXT_MENU_PROPS,\r\n type ContextMenuItem,\r\n type ContextMenuProps,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_ContextMenu' })\r\n\r\n const props = withDefaults(defineProps<ContextMenuProps>(), {\r\n items: () => [],\r\n minWidth: DEFAULT_CONTEXT_MENU_PROPS.minWidth,\r\n maxWidth: DEFAULT_CONTEXT_MENU_PROPS.maxWidth,\r\n subMenuPlacement: DEFAULT_CONTEXT_MENU_PROPS.subMenuPlacement,\r\n autoClose: DEFAULT_CONTEXT_MENU_PROPS.autoClose,\r\n disabled: DEFAULT_CONTEXT_MENU_PROPS.disabled,\r\n zIndex: DEFAULT_CONTEXT_MENU_PROPS.zIndex,\r\n })\r\n\r\n const emit = defineEmits<{\r\n (e: 'select', item: ContextMenuItem): void\r\n (e: 'open', position: { x: number; y: number }): void\r\n (e: 'close'): void\r\n }>()\r\n\r\n // ===== 状态 =====\r\n const visible = ref(false)\r\n const position = ref({ x: 0, y: 0 })\r\n const menuRef = ref<HTMLElement>()\r\n const activeSubKey = ref<string | null>(null)\r\n\r\n let subTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n // ===== 可见项 =====\r\n const visibleItems = computed(() => props.items.filter(item => !item.hidden))\r\n\r\n // ===== 菜单定位样式 =====\r\n const menuStyle = computed(() => ({\r\n left: `${position.value.x}px`,\r\n top: `${position.value.y}px`,\r\n minWidth: `${props.minWidth}px`,\r\n maxWidth: `${props.maxWidth}px`,\r\n zIndex: props.zIndex,\r\n }))\r\n\r\n // ===== 边界校正 =====\r\n const adjustPosition = () => {\r\n nextTick(() => {\r\n const el = menuRef.value\r\n if (!el) return\r\n const rect = el.getBoundingClientRect()\r\n const { innerWidth, innerHeight } = window\r\n\r\n if (rect.right > innerWidth) {\r\n position.value.x = innerWidth - rect.width - 8\r\n }\r\n if (rect.bottom > innerHeight) {\r\n position.value.y = innerHeight - rect.height - 8\r\n }\r\n if (position.value.x < 0) position.value.x = 8\r\n if (position.value.y < 0) position.value.y = 8\r\n })\r\n }\r\n\r\n // ===== 打开/关闭 =====\r\n const open = (x: number, y: number) => {\r\n if (props.disabled) return\r\n position.value = { x, y }\r\n visible.value = true\r\n emit('open', { x, y })\r\n adjustPosition()\r\n\r\n // 聚焦以支持 Escape 关闭\r\n nextTick(() => menuRef.value?.focus())\r\n }\r\n\r\n const close = () => {\r\n visible.value = false\r\n activeSubKey.value = null\r\n emit('close')\r\n }\r\n\r\n // ===== 菜单项点击 =====\r\n const handleItemClick = (item: ContextMenuItem) => {\r\n if (item.disabled) return\r\n if (item.children?.length) return // 有子菜单不触发\r\n\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 子菜单悬停 =====\r\n const handleMouseEnter = (item: ContextMenuItem) => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n if (item.children?.length && !item.disabled) {\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = item.key\r\n }, 150)\r\n } else {\r\n activeSubKey.value = null\r\n }\r\n }\r\n\r\n const handleMouseLeave = () => {\r\n if (subTimer) {\r\n clearTimeout(subTimer)\r\n subTimer = null\r\n }\r\n subTimer = setTimeout(() => {\r\n activeSubKey.value = null\r\n }, 300)\r\n }\r\n\r\n // ===== 子菜单选择向上冒泡 =====\r\n const handleSubSelect = (item: ContextMenuItem) => {\r\n emit('select', item)\r\n if (props.autoClose) close()\r\n }\r\n\r\n // ===== 暴露 API =====\r\n defineExpose({\r\n /** 在指定坐标打开菜单 */\r\n open,\r\n /** 关闭菜单 */\r\n close,\r\n /** 当前是否可见 */\r\n visible: computed(() => visible.value),\r\n })\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_ContextMenu.js","names":[],"sources":["../src/components/C_ContextMenu/types.ts","../src/components/C_ContextMenu/index.vue"],"sourcesContent":["/**\n * @Description: 右键菜单组件类型定义\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\n/** 菜单项 */\nexport interface ContextMenuItem {\n /** 唯一标识 */\n key: string\n /** 菜单文字 */\n label: string\n /** 图标(Iconify 图标名) */\n icon?: string\n /** 快捷键标注文字(仅展示,不绑定) */\n shortcut?: string\n /** 是否禁用 */\n disabled?: boolean\n /** 是否隐藏 */\n hidden?: boolean\n /** 分割线(此项渲染为分割线,label 被忽略) */\n divider?: boolean\n /** 子菜单(支持无限嵌套) */\n children?: ContextMenuItem[]\n /** 自定义样式类 */\n className?: string\n /** 危险操作(红色高亮) */\n danger?: boolean\n}\n\n/** 组件 Props */\nexport interface ContextMenuProps {\n /** 菜单项列表 */\n items: ContextMenuItem[]\n /** 菜单最小宽度 */\n minWidth?: number\n /** 菜单最大宽度 */\n maxWidth?: number\n /** 子菜单展开方向 */\n subMenuPlacement?: 'right' | 'left'\n /** 点击菜单项后是否自动关闭 */\n autoClose?: boolean\n /** 是否禁用整个菜单 */\n disabled?: boolean\n /** 自定义 z-index */\n zIndex?: number\n}\n\n/** 默认 Props */\nexport const DEFAULT_CONTEXT_MENU_PROPS = {\n minWidth: 180,\n maxWidth: 280,\n subMenuPlacement: 'right' as const,\n autoClose: true,\n disabled: false,\n zIndex: 9999,\n}\n","<!--\n * @Description: 右键菜单组件 — 声明式配置、快捷键标注、嵌套子菜单\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <!-- 遮罩层 -->\n <Teleport to=\"body\">\n <div\n v-if=\"visible\"\n class=\"c-context-menu-overlay\"\n :style=\"{ zIndex: props.zIndex - 1 }\"\n @click=\"close\"\n @contextmenu.prevent=\"close\"\n />\n\n <!-- 菜单面板 -->\n <div\n v-if=\"visible\"\n ref=\"menuRef\"\n class=\"c-context-menu\"\n :style=\"menuStyle\"\n role=\"menu\"\n tabindex=\"-1\"\n @keydown.escape=\"close\"\n >\n <template\n v-for=\"item in visibleItems\"\n :key=\"item.key\"\n >\n <!-- 分割线 -->\n <div\n v-if=\"item.divider\"\n class=\"c-context-menu__divider\"\n role=\"separator\"\n />\n\n <!-- 普通菜单项 -->\n <div\n v-else\n :class=\"[\n 'c-context-menu__item',\n {\n 'is-disabled': item.disabled,\n 'is-danger': item.danger,\n },\n ]\"\n role=\"menuitem\"\n :aria-disabled=\"item.disabled\"\n @click=\"handleItemClick(item)\"\n @mouseenter=\"handleMouseEnter(item)\"\n @mouseleave=\"handleMouseLeave\"\n >\n <!-- 图标 -->\n <span\n v-if=\"item.icon\"\n class=\"c-context-menu__icon\"\n >\n <C_Icon :name=\"item.icon\" />\n </span>\n\n <!-- 文本 -->\n <span class=\"c-context-menu__label\">{{ item.label }}</span>\n\n <!-- 快捷键 -->\n <span\n v-if=\"item.shortcut\"\n class=\"c-context-menu__shortcut\"\n >\n {{ item.shortcut }}\n </span>\n\n <!-- 子菜单箭头 -->\n <span\n v-if=\"item.children?.length\"\n class=\"c-context-menu__arrow\"\n >\n <C_Icon name=\"mdi:chevron-right\" />\n </span>\n\n <!-- 子菜单(递归) -->\n <C_ContextMenu\n v-if=\"item.children?.length && activeSubKey === item.key\"\n :items=\"item.children\"\n :min-width=\"props.minWidth\"\n :max-width=\"props.maxWidth\"\n :sub-menu-placement=\"props.subMenuPlacement\"\n :auto-close=\"props.autoClose\"\n :z-index=\"props.zIndex + 1\"\n class=\"c-context-menu__submenu\"\n :class=\"`is-${props.subMenuPlacement}`\"\n :style=\"{ position: 'absolute' }\"\n @select=\"handleSubSelect\"\n />\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\n import { computed, nextTick, ref } from 'vue'\n import C_Icon from '../C_Icon/index.vue'\n import {\n DEFAULT_CONTEXT_MENU_PROPS,\n type ContextMenuItem,\n type ContextMenuProps,\n } from './types'\n\n defineOptions({ name: 'C_ContextMenu' })\n\n const props = withDefaults(defineProps<ContextMenuProps>(), {\n items: () => [],\n minWidth: DEFAULT_CONTEXT_MENU_PROPS.minWidth,\n maxWidth: DEFAULT_CONTEXT_MENU_PROPS.maxWidth,\n subMenuPlacement: DEFAULT_CONTEXT_MENU_PROPS.subMenuPlacement,\n autoClose: DEFAULT_CONTEXT_MENU_PROPS.autoClose,\n disabled: DEFAULT_CONTEXT_MENU_PROPS.disabled,\n zIndex: DEFAULT_CONTEXT_MENU_PROPS.zIndex,\n })\n\n const emit = defineEmits<{\n (e: 'select', item: ContextMenuItem): void\n (e: 'open', position: { x: number; y: number }): void\n (e: 'close'): void\n }>()\n\n // ===== 状态 =====\n const visible = ref(false)\n const position = ref({ x: 0, y: 0 })\n const menuRef = ref<HTMLElement>()\n const activeSubKey = ref<string | null>(null)\n\n let subTimer: ReturnType<typeof setTimeout> | null = null\n\n // ===== 可见项 =====\n const visibleItems = computed(() => props.items.filter(item => !item.hidden))\n\n // ===== 菜单定位样式 =====\n const menuStyle = computed(() => ({\n left: `${position.value.x}px`,\n top: `${position.value.y}px`,\n minWidth: `${props.minWidth}px`,\n maxWidth: `${props.maxWidth}px`,\n zIndex: props.zIndex,\n }))\n\n // ===== 边界校正 =====\n const adjustPosition = () => {\n nextTick(() => {\n const el = menuRef.value\n if (!el) return\n const rect = el.getBoundingClientRect()\n const { innerWidth, innerHeight } = window\n\n if (rect.right > innerWidth) {\n position.value.x = innerWidth - rect.width - 8\n }\n if (rect.bottom > innerHeight) {\n position.value.y = innerHeight - rect.height - 8\n }\n if (position.value.x < 0) position.value.x = 8\n if (position.value.y < 0) position.value.y = 8\n })\n }\n\n // ===== 打开/关闭 =====\n const open = (x: number, y: number) => {\n if (props.disabled) return\n position.value = { x, y }\n visible.value = true\n emit('open', { x, y })\n adjustPosition()\n\n // 聚焦以支持 Escape 关闭\n nextTick(() => menuRef.value?.focus())\n }\n\n const close = () => {\n visible.value = false\n activeSubKey.value = null\n emit('close')\n }\n\n // ===== 菜单项点击 =====\n const handleItemClick = (item: ContextMenuItem) => {\n if (item.disabled) return\n if (item.children?.length) return // 有子菜单不触发\n\n emit('select', item)\n if (props.autoClose) close()\n }\n\n // ===== 子菜单悬停 =====\n const handleMouseEnter = (item: ContextMenuItem) => {\n if (subTimer) {\n clearTimeout(subTimer)\n subTimer = null\n }\n if (item.children?.length && !item.disabled) {\n subTimer = setTimeout(() => {\n activeSubKey.value = item.key\n }, 150)\n } else {\n activeSubKey.value = null\n }\n }\n\n const handleMouseLeave = () => {\n if (subTimer) {\n clearTimeout(subTimer)\n subTimer = null\n }\n subTimer = setTimeout(() => {\n activeSubKey.value = null\n }, 300)\n }\n\n // ===== 子菜单选择向上冒泡 =====\n const handleSubSelect = (item: ContextMenuItem) => {\n emit('select', item)\n if (props.autoClose) close()\n }\n\n // ===== 暴露 API =====\n defineExpose({\n /** 在指定坐标打开菜单 */\n open,\n /** 关闭菜单 */\n close,\n /** 当前是否可见 */\n visible: computed(() => visible.value),\n })\n</script>\n\n<style scoped lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|