@robot-admin/naive-ui-components 0.9.2 → 0.10.0
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/CHANGELOG.md +82 -76
- package/LICENSE +21 -0
- package/README.md +314 -294
- package/dist/C_ActionBar-BAcfOfRw.css.map +1 -0
- package/dist/C_ActionBar-DG2HW7t5.css.map +1 -0
- package/dist/C_ActionBar.css +47 -47
- 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-BY8jqqmi.css.map → C_AntV-D_jTK8oZ.css.map} +1 -1
- package/dist/{C_AntV-BbkHc-_a.css.map → C_AntV-DanTAq22.css.map} +1 -1
- package/dist/C_AntV.css +79 -79
- 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-DKRIGhi7.css.map → C_AudioPlayer-BnYIJXPD.css.map} +1 -1
- package/dist/{C_AudioPlayer-DlB6eNsa.css.map → C_AudioPlayer-ldTy9Y34.css.map} +1 -1
- package/dist/C_AudioPlayer.css +47 -47
- 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-D02zci-i.css.map → C_AvatarGroup-B9d-GJ9c.css.map} +1 -1
- package/dist/{C_AvatarGroup-DatHaUlY.css.map → C_AvatarGroup-SIzxuuZr.css.map} +1 -1
- package/dist/C_AvatarGroup.cjs +1 -1
- package/dist/C_AvatarGroup.css +21 -21
- package/dist/C_AvatarGroup.d.cts +1 -1
- package/dist/C_AvatarGroup.d.ts +1 -1
- package/dist/C_AvatarGroup.js +1 -1
- 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-DYDRDe2O.css.map → C_Barcode-CAU2mFcx.css.map} +1 -1
- package/dist/{C_Barcode-muJdc_O4.css.map → C_Barcode-D2oJaEg3.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.js.map +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/{C_Captcha-9_hk6VmY.css.map → C_Captcha-B3yrtG7t.css.map} +1 -1
- package/dist/{C_Captcha-MtASlJ0f.css.map → C_Captcha-D4hDdWDu.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-CmCrLVft.css.map +1 -0
- package/dist/C_Cascade-U6A5AJJb.css.map +1 -0
- package/dist/C_Cascade.css +3 -3
- package/dist/C_Cascade.d.cts +2 -2
- package/dist/C_Cascade.d.ts +2 -2
- 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-Csjz_BFw.css.map → C_Chat-CF1SU7mc.css.map} +1 -1
- package/dist/{C_Chat-DO1ZBA_0.css.map → C_Chat-DeUv6uuI.css.map} +1 -1
- package/dist/C_Chat.css +65 -65
- 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-Bam08Qv3.css.map → C_City-DdkX6u64.css.map} +1 -1
- package/dist/{C_City-Bb3W-KaN.css.map → C_City-iP-dIvui.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-BWmJMNS7.css.map +1 -0
- package/dist/C_Code-k14vjgVl.css.map +1 -0
- package/dist/C_Code.css +3 -3
- 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-CWkFCqNQ.css.map → C_CollapsePanel-BSKcWSmY.css.map} +1 -1
- package/dist/{C_CollapsePanel-pcVJA_4z.css.map → C_CollapsePanel-DRvRq8tB.css.map} +1 -1
- package/dist/C_CollapsePanel.css +35 -35
- 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-B3Cgz_wJ.css.map → C_ContextMenu-Bn_uhJSo.css.map} +1 -1
- package/dist/{C_ContextMenu-u1LixF3_.css.map → C_ContextMenu-C9iuxG2n.css.map} +1 -1
- package/dist/C_ContextMenu.css +17 -17
- 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-Civir5-I.css.map → C_Cron-BIQ2By9v.css.map} +1 -1
- package/dist/{C_Cron-iw3qpMsy.css.map → C_Cron-BNSAGD6A.css.map} +1 -1
- package/dist/C_Cron.css +57 -57
- 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-BCjIvIwT.css.map → C_Draggable-BDAbk4s5.css.map} +1 -1
- package/dist/{C_Draggable-DwkSlCOS.css.map → C_Draggable-UhfDLXop.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 → C_Editor-CZOaChru.css.map} +1 -1
- package/dist/{C_Editor-Do2StvoJ.css.map → C_Editor-kJAQq5z6.css.map} +1 -1
- package/dist/C_Editor.css +14 -14
- 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-BhcbiXsV.css.map → C_FilePreview-Bs_omgJS.css.map} +1 -1
- package/dist/{C_FilePreview-DJudcIbW.css.map → C_FilePreview-DbwoyF2j.css.map} +1 -1
- package/dist/C_FilePreview.css +91 -91
- 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-BtcAPIRi.css.map → C_Form-B_2ql62V.css.map} +1 -1
- package/dist/{C_Form-D_gwQ7hC.css.map → C_Form-CX-7xsz3.css.map} +1 -1
- package/dist/C_Form.css +223 -223
- package/dist/C_Form.d.cts +2 -2
- package/dist/C_Form.d.ts +2 -2
- 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-Bi4XYjjk.css.map → C_FormSearch-C3F8peAY.css.map} +1 -1
- package/dist/{C_FormSearch-DUGOoX0u.css.map → C_FormSearch-qW56bJPo.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-CJk3SSUJ.css.map → C_FormulaEditor-ChOvDbsZ.css.map} +1 -1
- package/dist/{C_FormulaEditor-Cy7mjfVO.css.map → C_FormulaEditor-mfiIUDY4.css.map} +1 -1
- package/dist/C_FormulaEditor.css +78 -78
- 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-C2nsqrgS.css.map +1 -0
- package/dist/C_FullCalendar-DdFtXVhy.css.map +1 -0
- package/dist/C_FullCalendar.css +2 -2
- 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-B6wK3m3k.css.map → C_GlobalSearch-Dq4Wo01K.css.map} +1 -1
- package/dist/{C_GlobalSearch-DoPjldFm.css.map → C_GlobalSearch-RB7J43gu.css.map} +1 -1
- package/dist/C_GlobalSearch.css +112 -112
- package/dist/C_GlobalSearch.js.map +1 -1
- package/dist/C_GlobalSearch2.js +1 -1
- package/dist/C_GlobalSearch2.js.map +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.d.cts +1 -1
- package/dist/C_Icon.d.ts +1 -1
- package/dist/C_Icon.js.map +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/{C_ImageCropper-BqZpkZfU.css.map → C_ImageCropper-CdTX2nxU.css.map} +1 -1
- package/dist/{C_ImageCropper-CylwGuzS.css.map → C_ImageCropper-ilOqPklJ.css.map} +1 -1
- package/dist/C_ImageCropper.css +23 -23
- 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.d.cts +1 -1
- package/dist/C_Language.d.ts +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-BkdnkBKX.css.map → C_Login-B3qYkLrN.css.map} +1 -1
- package/dist/{C_Login-VkMM6OJ2.css.map → C_Login-xMI1_ojE.css.map} +1 -1
- package/dist/C_Login.css +72 -72
- 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-DNnBcY70.css.map → C_Map-CWMMN58_.css.map} +1 -1
- package/dist/{C_Map-LEXIx6zM.css.map → C_Map-xSR2H-9o.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-DwmI0_0Q.css.map → C_Markdown-C7lTVJ1S.css.map} +1 -1
- package/dist/{C_Markdown-k0794RW0.css.map → C_Markdown-CZDm_baQ.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-DT6fQ79O.css.map → C_NotificationCenter-D7GGGWg7.css.map} +1 -1
- package/dist/{C_NotificationCenter-DbgBiyqB.css.map → C_NotificationCenter-SSmeHA45.css.map} +1 -1
- package/dist/C_NotificationCenter.css +89 -89
- 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.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-CFNTda_1.css.map → C_QRCode-B_1lHUdx.css.map} +1 -1
- package/dist/{C_QRCode-CmWr9lK-.css.map → C_QRCode-CuQRYu0s.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-BDx4ctsE.css.map → C_Signature-Bp-RBpAl.css.map} +1 -1
- package/dist/{C_Signature-Bz_uNbwv.css.map → C_Signature-Cb2VW1ok.css.map} +1 -1
- package/dist/C_Signature.css +15 -15
- 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.map +1 -1
- package/dist/{C_SplitPane-BOwr1C7K.css.map → C_SplitPane-CgGWYsRE.css.map} +1 -1
- package/dist/{C_SplitPane-N-a_D-7F.css.map → C_SplitPane-DGf6WEeR.css.map} +1 -1
- package/dist/C_SplitPane.css +31 -31
- 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-27Exh7PM.css.map +1 -0
- package/dist/C_Steps-DU9ZsFrs.css.map +1 -0
- package/dist/C_Steps.css +38 -38
- package/dist/C_Steps.d.cts +1 -1
- package/dist/C_Steps.d.ts +1 -1
- 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-BcM5LqAM.css.map → C_Table--kbQaaBv.css.map} +1 -1
- package/dist/{C_Table-HATVoq1F.css.map → C_Table-D631kdXC.css.map} +1 -1
- package/dist/C_Table.css +104 -104
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +3 -3
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-DX3LecK1.css.map → C_TagsView-BN8vMRsY.css.map} +1 -1
- package/dist/{C_TagsView-DqOTa8bL.css.map → C_TagsView-s1dnSJAV.css.map} +1 -1
- package/dist/C_TagsView.css +36 -36
- package/dist/C_TagsView.d.cts +1 -1
- package/dist/C_TagsView.d.ts +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.d.cts +1 -1
- package/dist/C_Theme.d.ts +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-BQ9PGy8B.css.map +1 -0
- package/dist/C_Time-CO73krC6.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-BKkimrZx.css.map → C_Timeline-4rk0Dzgn.css.map} +1 -1
- package/dist/{C_Timeline-DTuSCX6p.css.map → C_Timeline-DdESmqwL.css.map} +1 -1
- package/dist/C_Timeline.cjs +1 -1
- package/dist/C_Timeline.css +45 -45
- package/dist/C_Timeline.d.cts +1 -1
- package/dist/C_Timeline.d.ts +1 -1
- 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-BOB6OBqS.css.map → C_Transfer-B-vjvhjI.css.map} +1 -1
- package/dist/{C_Transfer-Dpq7ezWC.css.map → C_Transfer-EzdHzZNv.css.map} +1 -1
- package/dist/C_Transfer.css +31 -31
- 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-D98nX9qT.css.map → C_Tree-CsXgGfhn.css.map} +1 -1
- package/dist/{C_Tree-ulfm7b-P.css.map → C_Tree-P7eRpnOa.css.map} +1 -1
- package/dist/C_Tree.css +33 -33
- 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-BR9fg5r4.css.map → C_Upload-CHjiVVh7.css.map} +1 -1
- package/dist/{C_Upload-CPqf74Ea.css.map → C_Upload-DE3OLsZD.css.map} +1 -1
- package/dist/C_Upload.css +50 -50
- 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-4J96tKfK.css.map → C_VideoPlayer-CnaNOFtW.css.map} +1 -1
- package/dist/{C_VideoPlayer-D35seHkm.css.map → C_VideoPlayer-cnP88zNV.css.map} +1 -1
- package/dist/C_VideoPlayer.css +68 -68
- 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-C2lxFmWg.css.map → C_VtableGantt-CZlJgvpC.css.map} +1 -1
- package/dist/{C_VtableGantt-Dwnkw_WL.css.map → C_VtableGantt-DKfQkql0.css.map} +1 -1
- package/dist/C_VtableGantt.css +15 -15
- 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-C4HDqf-a.css.map → C_WaterFall-BJ_39ext.css.map} +1 -1
- package/dist/{C_WaterFall-HWB-gPON.css.map → C_WaterFall-cYc1vntE.css.map} +1 -1
- package/dist/C_WaterFall.css +16 -16
- 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-2hJfvvTK.css.map → C_WorkFlow-BFzRGGhJ.css.map} +1 -1
- package/dist/{C_WorkFlow-DHoNjl8-.css.map → C_WorkFlow-DSyCOvRp.css.map} +1 -1
- package/dist/C_WorkFlow.css +193 -193
- 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 +1 -1
- package/dist/constants2.d.ts +1 -1
- package/dist/constants3.d.ts +1 -1
- package/dist/constants4.d.ts +2 -2
- package/dist/constants5.d.ts +2 -2
- package/dist/data.d.ts +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index10.vue.d.ts +2 -2
- package/dist/index11.vue.d.ts +2 -2
- package/dist/index12.vue.d.ts +1 -1
- package/dist/index13.vue.d.ts +2 -2
- package/dist/index14.vue.d.ts +2 -2
- package/dist/index15.vue.d.ts +29 -9
- package/dist/index16.vue.d.ts +11 -4
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index18.vue.d.ts +3 -3
- package/dist/index2.vue.d.ts +6 -6
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.ts +3 -3
- package/dist/index22.vue.d.ts +3 -3
- package/dist/index23.vue.d.ts +15 -4
- package/dist/index24.vue.d.ts +13 -4
- package/dist/index25.vue.d.ts +4 -2
- package/dist/index26.vue.d.ts +2 -2
- package/dist/index27.vue.d.ts +3 -3
- package/dist/index28.vue.d.ts +4 -4
- package/dist/index3.vue.d.ts +1 -1
- package/dist/index4.vue.d.ts +4 -4
- package/dist/index6.vue.d.ts +3 -3
- package/dist/index7.vue.d.ts +7 -5
- package/dist/resolver.cjs +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.d.cts +2 -21
- package/dist/resolver.d.ts +2 -21
- package/dist/resolver.js +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +1991 -1991
- package/dist/useCalendarEvents.d.ts +8 -5
- package/dist/useCollapsePanel.d.ts +2 -2
- package/dist/useCropperCore.d.ts +6 -6
- package/dist/useDraggableLayout.d.ts +3 -3
- package/dist/useDynamicFormState.d.ts +31 -3726
- package/dist/useEdgeInteraction.d.ts +2 -2
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.ts +2 -2
- package/dist/useModalEdit.d.ts +6 -6
- package/dist/useQRCode.d.ts +5 -5
- package/dist/useSignatureHistory.d.ts +2 -2
- package/dist/useSplitResize.d.ts +6 -6
- package/dist/useTimeSelection.d.ts +3 -3
- package/dist/useTreeOperations.d.ts +5 -5
- package/dist/useWorkflowValidation.d.ts +3 -3
- package/package.json +12 -7
- package/dist/C_ActionBar-DYG0Yf3A.css.map +0 -1
- package/dist/C_ActionBar-MAjRhqcI.css.map +0 -1
- package/dist/C_Cascade-Dq0S5Jkm.css.map +0 -1
- package/dist/C_Cascade-IUUHIh7r.css.map +0 -1
- package/dist/C_Code-BFi5xxnM.css.map +0 -1
- package/dist/C_Code-CZ7yfnri.css.map +0 -1
- package/dist/C_FullCalendar-BQA0OjGB.css.map +0 -1
- package/dist/C_FullCalendar-ChJUosAi.css.map +0 -1
- package/dist/C_Steps-Bk1krgiR.css.map +0 -1
- package/dist/C_Steps-Dn2CMpy1.css.map +0 -1
- package/dist/C_Time-BzyQVvTS.css.map +0 -1
- package/dist/C_Time-DmpKLQHc.css.map +0 -1
- package/dist/themes/glass-morphism.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_GlobalSearch.js","names":[],"sources":["../src/components/C_GlobalSearch/composables/useGlobalSearch.ts","../src/components/C_GlobalSearch/index.vue"],"sourcesContent":["import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\nimport type { SearchMenuItem, HistoryItem, GlobalSearchOptions } from '../types'\n\n/**\n * 全局搜索逻辑 — 管理菜单搜索、历史记录、键盘导航\n *\n * 已解耦:不依赖任何项目级 store / router,\n * 所有外部数据通过 options 注入。\n */\nexport function useGlobalSearch(options: GlobalSearchOptions) {\n const {\n menuItems: getMenuItems,\n isDark: getIsDark,\n onSelect,\n storageKey = 'robot-search-history',\n maxHistory = 10,\n maxDisplayHistory = 5,\n } = options\n\n // ==================== 响应式状态 ====================\n const showDialog = ref(false)\n const searchValue = ref('')\n const selectedIndex = ref(0)\n const searchInputRef = ref<HTMLInputElement>()\n const searchHistory = ref<HistoryItem[]>([])\n\n // ==================== 计算属性 ====================\n const isDark = computed(() => getIsDark?.() ?? false)\n\n const filteredMenuItems = computed(() => {\n if (!searchValue.value.trim()) return []\n const query = searchValue.value.toLowerCase()\n const items = getMenuItems()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n formatMenuPath(item.key).toLowerCase().includes(query)\n )\n })\n\n const displayHistory = computed(() =>\n searchHistory.value.slice(0, maxDisplayHistory)\n )\n const hasResults = computed(() => filteredMenuItems.value.length > 0)\n const hasContent = computed(\n () => hasResults.value || displayHistory.value.length > 0\n )\n\n // ==================== 工具函数 ====================\n const getItemClasses = (index: number, isHistory: boolean) => [\n 'robot-result-item',\n isHistory && 'robot-history-item',\n { 'robot-result-item-selected': selectedIndex.value === index },\n ]\n\n const highlightMatch = (text: string, search: string): string => {\n if (!search) return text\n const regex = new RegExp(\n `(${search.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n 'gi'\n )\n return text.replace(regex, '<mark class=\"robot-highlight\">$1</mark>')\n }\n\n const formatMenuPath = (key: string): string =>\n key.replace(/^\\//, '').replace(/\\//g, ' > ') || '首页'\n\n // ==================== 搜索历史管理 ====================\n const addToHistory = (menuItem: SearchMenuItem) => {\n if (!menuItem.label.trim()) return\n const query = menuItem.label\n const filtered = searchHistory.value.filter(\n (item: HistoryItem) =>\n !(item.query === query && item.menuItem?.key === menuItem.key)\n )\n searchHistory.value = [\n { query, menuItem, timestamp: Date.now() },\n ...filtered,\n ].slice(0, maxHistory)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n }\n\n const loadHistory = () => {\n try {\n const saved = localStorage.getItem(storageKey)\n if (saved) {\n const parsed = JSON.parse(saved)\n searchHistory.value = parsed.map((item: any) =>\n typeof item === 'string'\n ? { query: item, menuItem: null, timestamp: 0 }\n : item\n )\n }\n } catch (error) {\n console.error('加载搜索历史失败:', error)\n }\n }\n\n const clearHistory = () => {\n searchHistory.value = []\n localStorage.removeItem(storageKey)\n }\n\n const removeHistoryItem = (index: number) => {\n searchHistory.value.splice(index, 1)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n if (selectedIndex.value >= searchHistory.value.length) {\n selectedIndex.value = Math.max(0, searchHistory.value.length - 1)\n }\n }\n\n // ==================== 对话框控制 ====================\n const openDialog = async () => {\n showDialog.value = true\n searchValue.value = ''\n selectedIndex.value = 0\n await nextTick()\n searchInputRef.value?.focus()\n }\n\n const closeDialog = () => {\n showDialog.value = false\n searchValue.value = ''\n selectedIndex.value = 0\n }\n\n // ==================== 选择项目 ====================\n const selectHistoryItem = (historyItem: HistoryItem) => {\n if (historyItem.menuItem) {\n const hasChildren = !!historyItem.menuItem.children?.length\n onSelect?.(historyItem.menuItem.key, hasChildren)\n closeDialog()\n } else {\n searchValue.value = historyItem.query\n selectedIndex.value = 0\n }\n }\n\n const selectItem = (item: SearchMenuItem) => {\n addToHistory(item)\n const hasChildren = !!item.children?.length\n onSelect?.(item.key, hasChildren)\n closeDialog()\n }\n\n // ==================== 键盘导航 ====================\n const handleEnter = () => {\n const isHistoryMode =\n !searchValue.value.trim() && displayHistory.value.length > 0\n const isSearchMode =\n searchValue.value.trim() && filteredMenuItems.value.length > 0\n\n if (isHistoryMode) {\n const historyItem = displayHistory.value[selectedIndex.value]\n if (historyItem) selectHistoryItem(historyItem)\n } else if (isSearchMode) {\n const item = filteredMenuItems.value[selectedIndex.value]\n if (item) selectItem(item)\n }\n }\n\n const focusNext = () => {\n const maxIndex = !searchValue.value.trim()\n ? displayHistory.value.length - 1\n : filteredMenuItems.value.length - 1\n selectedIndex.value = Math.min(selectedIndex.value + 1, maxIndex)\n }\n\n const focusPrev = () => {\n selectedIndex.value = Math.max(selectedIndex.value - 1, 0)\n }\n\n // ==================== 监听器和生命周期 ====================\n watch(searchValue, () => {\n selectedIndex.value = 0\n })\n\n onMounted(() => {\n loadHistory()\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n e.preventDefault()\n openDialog()\n }\n }\n document.addEventListener('keydown', handleKeydown)\n onUnmounted(() => document.removeEventListener('keydown', handleKeydown))\n })\n\n return {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n }\n}\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_GlobalSearch.js","names":["placeholder","emptyText","resultGroupTitle"],"sources":["../src/components/C_GlobalSearch/composables/useGlobalSearch.ts","../src/components/C_GlobalSearch/index.vue","../src/components/C_GlobalSearch/index.vue"],"sourcesContent":["import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\nimport type { SearchMenuItem, HistoryItem, GlobalSearchOptions } from '../types'\n\n/**\n * 全局搜索逻辑 — 管理菜单搜索、历史记录、键盘导航\n *\n * 已解耦:不依赖任何项目级 store / router,\n * 所有外部数据通过 options 注入。\n */\nexport function useGlobalSearch(options: GlobalSearchOptions) {\n const {\n menuItems: getMenuItems,\n isDark: getIsDark,\n onSelect,\n storageKey = 'robot-search-history',\n maxHistory = 10,\n maxDisplayHistory = 5,\n } = options\n\n // ==================== 响应式状态 ====================\n const showDialog = ref(false)\n const searchValue = ref('')\n const selectedIndex = ref(0)\n const searchInputRef = ref<HTMLInputElement>()\n const searchHistory = ref<HistoryItem[]>([])\n\n // ==================== 计算属性 ====================\n const isDark = computed(() => getIsDark?.() ?? false)\n\n const filteredMenuItems = computed(() => {\n if (!searchValue.value.trim()) return []\n const query = searchValue.value.toLowerCase()\n const items = getMenuItems()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n formatMenuPath(item.key).toLowerCase().includes(query)\n )\n })\n\n const displayHistory = computed(() =>\n searchHistory.value.slice(0, maxDisplayHistory)\n )\n const hasResults = computed(() => filteredMenuItems.value.length > 0)\n const hasContent = computed(\n () => hasResults.value || displayHistory.value.length > 0\n )\n\n // ==================== 工具函数 ====================\n const getItemClasses = (index: number, isHistory: boolean) => [\n 'robot-result-item',\n isHistory && 'robot-history-item',\n { 'robot-result-item-selected': selectedIndex.value === index },\n ]\n\n const highlightMatch = (text: string, search: string): string => {\n if (!search) return text\n const regex = new RegExp(\n `(${search.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n 'gi'\n )\n return text.replace(regex, '<mark class=\"robot-highlight\">$1</mark>')\n }\n\n const formatMenuPath = (key: string): string =>\n key.replace(/^\\//, '').replace(/\\//g, ' > ') || '首页'\n\n // ==================== 搜索历史管理 ====================\n const addToHistory = (menuItem: SearchMenuItem) => {\n if (!menuItem.label.trim()) return\n const query = menuItem.label\n const filtered = searchHistory.value.filter(\n (item: HistoryItem) =>\n !(item.query === query && item.menuItem?.key === menuItem.key)\n )\n searchHistory.value = [\n { query, menuItem, timestamp: Date.now() },\n ...filtered,\n ].slice(0, maxHistory)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n }\n\n const loadHistory = () => {\n try {\n const saved = localStorage.getItem(storageKey)\n if (saved) {\n const parsed = JSON.parse(saved)\n searchHistory.value = parsed.map((item: any) =>\n typeof item === 'string'\n ? { query: item, menuItem: null, timestamp: 0 }\n : item\n )\n }\n } catch (error) {\n console.error('加载搜索历史失败:', error)\n }\n }\n\n const clearHistory = () => {\n searchHistory.value = []\n localStorage.removeItem(storageKey)\n }\n\n const removeHistoryItem = (index: number) => {\n searchHistory.value.splice(index, 1)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n if (selectedIndex.value >= searchHistory.value.length) {\n selectedIndex.value = Math.max(0, searchHistory.value.length - 1)\n }\n }\n\n // ==================== 对话框控制 ====================\n const openDialog = async () => {\n showDialog.value = true\n searchValue.value = ''\n selectedIndex.value = 0\n await nextTick()\n searchInputRef.value?.focus()\n }\n\n const closeDialog = () => {\n showDialog.value = false\n searchValue.value = ''\n selectedIndex.value = 0\n }\n\n // ==================== 选择项目 ====================\n const selectHistoryItem = (historyItem: HistoryItem) => {\n if (historyItem.menuItem) {\n const hasChildren = !!historyItem.menuItem.children?.length\n onSelect?.(historyItem.menuItem.key, hasChildren)\n closeDialog()\n } else {\n searchValue.value = historyItem.query\n selectedIndex.value = 0\n }\n }\n\n const selectItem = (item: SearchMenuItem) => {\n addToHistory(item)\n const hasChildren = !!item.children?.length\n onSelect?.(item.key, hasChildren)\n closeDialog()\n }\n\n // ==================== 键盘导航 ====================\n const handleEnter = () => {\n const isHistoryMode =\n !searchValue.value.trim() && displayHistory.value.length > 0\n const isSearchMode =\n searchValue.value.trim() && filteredMenuItems.value.length > 0\n\n if (isHistoryMode) {\n const historyItem = displayHistory.value[selectedIndex.value]\n if (historyItem) selectHistoryItem(historyItem)\n } else if (isSearchMode) {\n const item = filteredMenuItems.value[selectedIndex.value]\n if (item) selectItem(item)\n }\n }\n\n const focusNext = () => {\n const maxIndex = !searchValue.value.trim()\n ? displayHistory.value.length - 1\n : filteredMenuItems.value.length - 1\n selectedIndex.value = Math.min(selectedIndex.value + 1, maxIndex)\n }\n\n const focusPrev = () => {\n selectedIndex.value = Math.max(selectedIndex.value - 1, 0)\n }\n\n // ==================== 监听器和生命周期 ====================\n watch(searchValue, () => {\n selectedIndex.value = 0\n })\n\n onMounted(() => {\n loadHistory()\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n e.preventDefault()\n openDialog()\n }\n }\n document.addEventListener('keydown', handleKeydown)\n onUnmounted(() => document.removeEventListener('keydown', handleKeydown))\n })\n\n return {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n }\n}\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
package/dist/C_GlobalSearch2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./export-helper.js";import{Fragment as t,Teleport 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,isRef as f,nextTick as p,normalizeClass as m,onMounted as h,onUnmounted as g,openBlock as _,ref as v,renderList as y,resolveDynamicComponent as b,toDisplayString as x,unref as S,vModelText as C,watch as w,withCtx as T,withDirectives as E,withKeys as D,withModifiers as O}from"vue";function k(e){let{menuItems:t,isDark:n,onSelect:r,storageKey:a=`robot-search-history`,maxHistory:o=10,maxDisplayHistory:s=5}=e,c=v(!1),l=v(``),u=v(0),d=v(),f=v([]),m=i(()=>n?.()??!1),_=i(()=>{if(!l.value.trim())return[];let e=l.value.toLowerCase();return t().filter(t=>t.label.toLowerCase().includes(e)||T(t.key).toLowerCase().includes(e))}),y=i(()=>f.value.slice(0,s)),b=i(()=>_.value.length>0),x=i(()=>b.value||y.value.length>0),S=(e,t)=>[`robot-result-item`,t&&`robot-history-item`,{"robot-result-item-selected":u.value===e}],C=(e,t)=>{if(!t)return e;let n=RegExp(`(${t.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)})`,`gi`);return e.replace(n,`<mark class="robot-highlight">$1</mark>`)},T=e=>e.replace(/^\//,``).replace(/\//g,` > `)||`首页`,E=e=>{if(!e.label.trim())return;let t=e.label,n=f.value.filter(n=>!(n.query===t&&n.menuItem?.key===e.key));f.value=[{query:t,menuItem:e,timestamp:Date.now()},...n].slice(0,o),localStorage.setItem(a,JSON.stringify(f.value))},D=()=>{try{let e=localStorage.getItem(a);e&&(f.value=JSON.parse(e).map(e=>typeof e==`string`?{query:e,menuItem:null,timestamp:0}:e))}catch(e){console.error(`加载搜索历史失败:`,e)}},O=()=>{f.value=[],localStorage.removeItem(a)},k=e=>{f.value.splice(e,1),localStorage.setItem(a,JSON.stringify(f.value)),u.value>=f.value.length&&(u.value=Math.max(0,f.value.length-1))},A=async()=>{c.value=!0,l.value=``,u.value=0,await p(),d.value?.focus()},j=()=>{c.value=!1,l.value=``,u.value=0},M=e=>{if(e.menuItem){let t=!!e.menuItem.children?.length;r?.(e.menuItem.key,t),j()}else l.value=e.query,u.value=0},N=e=>{E(e);let t=!!e.children?.length;r?.(e.key,t),j()};return w(l,()=>{u.value=0}),h(()=>{D();let e=e=>{(e.ctrlKey||e.metaKey)&&e.key===`k`&&(e.preventDefault(),A())};document.addEventListener(`keydown`,e),g(()=>document.removeEventListener(`keydown`,e))}),{showDialog:c,searchValue:l,selectedIndex:u,searchInputRef:d,isDark:m,filteredMenuItems:_,displayHistory:y,hasResults:b,hasContent:x,getItemClasses:S,highlightMatch:C,formatMenuPath:T,clearHistory:O,removeHistoryItem:k,openDialog:A,closeDialog:j,selectHistoryItem:M,selectItem:N,handleEnter:()=>{let e=!l.value.trim()&&y.value.length>0,t=l.value.trim()&&_.value.length>0;if(e){let e=y.value[u.value];e&&M(e)}else if(t){let e=_.value[u.value];e&&N(e)}},focusNext:()=>{let e=l.value.trim()?_.value.length-1:y.value.length-1;u.value=Math.min(u.value+1,e)},focusPrev:()=>{u.value=Math.max(u.value-1,0)}}}const A={class:`robot-search-palette`},j={class:`robot-search-header`},M=[`placeholder`],N={class:`robot-search-content`},ee={key:0,class:`robot-empty-state`},te={class:`robot-search-results`},P={class:`robot-result-group`},ne={class:`robot-group-title`},re={class:`robot-group-count`},ie={class:`robot-group-items`},ae=[`onClick`,`onMouseenter`],oe={key:1,class:`robot-item-icon robot-default-icon`},se={class:`robot-item-content`},ce={class:`robot-item-label`},le={class:`robot-item-desc`},ue=[`onClick`],de={class:`robot-search-results`},F={key:0,class:`robot-empty-state`},I={class:`robot-result-group`},L={class:`robot-group-title`},R={class:`robot-group-count`},z={class:`robot-group-items`},B=[`onClick`,`onMouseenter`],V={key:1,class:`robot-item-icon robot-default-icon`},fe={class:`robot-item-content`},H=[`innerHTML`],pe={class:`robot-item-desc`},me={key:2,class:`robot-item-badge`},he={class:`robot-search-footer`},ge={key:0,class:`robot-footer-info`},_e={key:0},ve={key:1};var U=e(d({name:`C_GlobalSearch`,__name:`index`,props:{options:{},placeholder:{default:`搜索导航菜单...`},emptyText:{default:`输入关键词搜索菜单`},resultGroupTitle:{default:`菜单导航`}},setup(e,{expose:i}){let{showDialog:d,searchValue:p,selectedIndex:h,searchInputRef:g,isDark:v,filteredMenuItems:w,displayHistory:U,hasResults:W,hasContent:G,getItemClasses:K,highlightMatch:ye,formatMenuPath:q,clearHistory:J,removeHistoryItem:be,openDialog:Y,closeDialog:X,selectHistoryItem:xe,selectItem:Se,handleEnter:Z,focusNext:Q,focusPrev:$}=k(e.options);return i({openDialog:Y,closeDialog:X}),(e,i)=>(_(),s(`div`,A,[o(` 搜索触发按钮 `),c(`div`,{class:m([`robot-search-trigger`,{"trigger-dark":S(v)}]),onClick:i[0]||=(...e)=>S(Y)&&S(Y)(...e)},i[11]||=[c(`div`,{class:`i-mdi:search robot-trigger-icon`},null,-1),c(`span`,{class:`robot-trigger-text`},`搜索`,-1),c(`span`,{class:`robot-trigger-shortcut`},`Ctrl K`,-1)],2),o(` 搜索对话框 `),(_(),a(n,{to:`body`},[u(r,{name:`robot-dialog`},{default:T(()=>[S(d)?(_(),s(`div`,{key:0,class:`robot-dialog-overlay`,onClick:i[9]||=(...e)=>S(X)&&S(X)(...e),onKeydown:i[10]||=D((...e)=>S(X)&&S(X)(...e),[`esc`])},[c(`div`,{class:m([`robot-dialog-container`,{"dialog-dark":S(v)}]),onClick:i[8]||=O(()=>{},[`stop`])},[o(` 搜索头部 `),c(`div`,j,[i[13]||=c(`div`,{class:`i-mdi:magnify robot-search-icon`},null,-1),E(c(`input`,{ref_key:`searchInputRef`,ref:g,"onUpdate:modelValue":i[1]||=e=>f(p)?p.value=e:null,type:`text`,placeholder:e.placeholder,class:`robot-search-input`,onKeydown:[i[2]||=D((...e)=>S(X)&&S(X)(...e),[`esc`]),i[3]||=D((...e)=>S(Z)&&S(Z)(...e),[`enter`]),i[4]||=D((...e)=>S(Q)&&S(Q)(...e),[`arrow-down`]),i[5]||=D((...e)=>S($)&&S($)(...e),[`arrow-up`])]},null,40,M),[[C,S(p)]]),c(`button`,{class:`robot-close-btn`,onClick:i[6]||=(...e)=>S(X)&&S(X)(...e)},i[12]||=[c(`div`,{class:`i-mdi:close`},null,-1)])]),o(` 搜索内容 `),c(`div`,N,[o(` 空状态 `),S(G)?!S(p).trim()&&S(U).length>0?(_(),s(t,{key:1},[o(` 搜索历史 `),c(`div`,te,[c(`div`,P,[c(`div`,ne,[i[16]||=c(`div`,{class:`i-mdi:clock-time-four-outline robot-group-icon`},null,-1),i[17]||=l(` 最近搜索 `,-1),c(`span`,re,x(S(U).length),1),c(`button`,{class:`robot-clear-history`,onClick:i[7]||=(...e)=>S(J)&&S(J)(...e),title:`清空历史`},i[15]||=[c(`div`,{class:`i-mdi:delete-outline`},null,-1)])]),c(`div`,ie,[(_(!0),s(t,null,y(S(U),(e,t)=>(_(),s(`div`,{key:`history-${t}`,class:m(S(K)(t,!0)),onClick:t=>S(xe)(e),onMouseenter:e=>h.value=t},[e.menuItem?.icon?(_(),a(b(e.menuItem.icon),{key:0,class:`robot-item-icon`})):(_(),s(`div`,oe,i[18]||=[c(`div`,{class:`i-mdi:file-document-outline`},null,-1)])),c(`div`,se,[c(`div`,ce,x(e.query),1),c(`div`,le,x(S(q)(e.menuItem?.key||``)),1)]),c(`button`,{class:`robot-history-delete`,onClick:O(e=>S(be)(t),[`stop`]),title:`删除此记录`},i[19]||=[c(`div`,{class:`i-mdi:close`},null,-1)],8,ue)],42,ae))),128))])])])],64)):S(p).trim()?(_(),s(t,{key:2},[o(` 搜索结果 `),c(`div`,de,[o(` 无结果状态 `),S(W)?(_(),s(t,{key:1},[o(` 搜索结果列表 `),c(`div`,I,[c(`div`,L,[i[21]||=c(`div`,{class:`i-mdi:menu robot-group-icon`},null,-1),l(` `+x(e.resultGroupTitle)+` `,1),c(`span`,R,x(S(w).length),1)]),c(`div`,z,[(_(!0),s(t,null,y(S(w),(e,t)=>(_(),s(`div`,{key:e.key,class:m(S(K)(t,!1)),onClick:t=>S(Se)(e),onMouseenter:e=>h.value=t},[e.icon?(_(),a(b(e.icon),{key:0,class:`robot-item-icon`})):(_(),s(`div`,V,i[22]||=[c(`div`,{class:`i-mdi:file-document-outline`},null,-1)])),c(`div`,fe,[c(`div`,{class:`robot-item-label`,innerHTML:S(ye)(e.label,S(p))},null,8,H),c(`div`,pe,x(S(q)(e.key)),1)]),e.children?.length?(_(),s(`div`,me,x(e.children.length),1)):o(`v-if`,!0)],42,B))),128))])])],2112)):(_(),s(`div`,F,[i[20]||=c(`div`,{class:`i-mdi:magnify robot-empty-icon`},null,-1),c(`p`,null,`未找到 "`+x(S(p))+`" 相关内容`,1)]))])],64)):o(`v-if`,!0):(_(),s(`div`,ee,[i[14]||=c(`div`,{class:`i-mdi:magnify robot-empty-icon`},null,-1),c(`p`,null,x(e.emptyText),1)]))]),o(` 搜索底部 `),c(`div`,he,[i[23]||=c(`div`,{class:`robot-footer-actions`},[c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`↵`),c(`span`,null,`选择`)]),c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`↑↓`),c(`span`,null,`导航`)]),c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`esc`),c(`span`,null,`关闭`)])],-1),S(G)?(_(),s(`div`,ge,[S(p).trim()&&S(W)?(_(),s(`span`,_e,` 共 `+x(S(w).length)+` 项结果 `,1)):!S(p).trim()&&S(U).length>0?(_(),s(`span`,ve,x(S(U).length)+` 条历史记录 `,1)):o(`v-if`,!0)])):o(`v-if`,!0)])],2)],32)):o(`v-if`,!0)]),_:1})]))]))}}),[[`__scopeId`,`data-v-
|
|
1
|
+
import{t as e}from"./export-helper.js";import{Fragment as t,Teleport 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,isRef as f,nextTick as p,normalizeClass as m,onMounted as h,onUnmounted as g,openBlock as _,ref as v,renderList as y,resolveDynamicComponent as b,toDisplayString as x,unref as S,vModelText as C,watch as w,withCtx as T,withDirectives as E,withKeys as D,withModifiers as O}from"vue";function k(e){let{menuItems:t,isDark:n,onSelect:r,storageKey:a=`robot-search-history`,maxHistory:o=10,maxDisplayHistory:s=5}=e,c=v(!1),l=v(``),u=v(0),d=v(),f=v([]),m=i(()=>n?.()??!1),_=i(()=>{if(!l.value.trim())return[];let e=l.value.toLowerCase();return t().filter(t=>t.label.toLowerCase().includes(e)||T(t.key).toLowerCase().includes(e))}),y=i(()=>f.value.slice(0,s)),b=i(()=>_.value.length>0),x=i(()=>b.value||y.value.length>0),S=(e,t)=>[`robot-result-item`,t&&`robot-history-item`,{"robot-result-item-selected":u.value===e}],C=(e,t)=>{if(!t)return e;let n=RegExp(`(${t.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)})`,`gi`);return e.replace(n,`<mark class="robot-highlight">$1</mark>`)},T=e=>e.replace(/^\//,``).replace(/\//g,` > `)||`首页`,E=e=>{if(!e.label.trim())return;let t=e.label,n=f.value.filter(n=>!(n.query===t&&n.menuItem?.key===e.key));f.value=[{query:t,menuItem:e,timestamp:Date.now()},...n].slice(0,o),localStorage.setItem(a,JSON.stringify(f.value))},D=()=>{try{let e=localStorage.getItem(a);e&&(f.value=JSON.parse(e).map(e=>typeof e==`string`?{query:e,menuItem:null,timestamp:0}:e))}catch(e){console.error(`加载搜索历史失败:`,e)}},O=()=>{f.value=[],localStorage.removeItem(a)},k=e=>{f.value.splice(e,1),localStorage.setItem(a,JSON.stringify(f.value)),u.value>=f.value.length&&(u.value=Math.max(0,f.value.length-1))},A=async()=>{c.value=!0,l.value=``,u.value=0,await p(),d.value?.focus()},j=()=>{c.value=!1,l.value=``,u.value=0},M=e=>{if(e.menuItem){let t=!!e.menuItem.children?.length;r?.(e.menuItem.key,t),j()}else l.value=e.query,u.value=0},N=e=>{E(e);let t=!!e.children?.length;r?.(e.key,t),j()};return w(l,()=>{u.value=0}),h(()=>{D();let e=e=>{(e.ctrlKey||e.metaKey)&&e.key===`k`&&(e.preventDefault(),A())};document.addEventListener(`keydown`,e),g(()=>document.removeEventListener(`keydown`,e))}),{showDialog:c,searchValue:l,selectedIndex:u,searchInputRef:d,isDark:m,filteredMenuItems:_,displayHistory:y,hasResults:b,hasContent:x,getItemClasses:S,highlightMatch:C,formatMenuPath:T,clearHistory:O,removeHistoryItem:k,openDialog:A,closeDialog:j,selectHistoryItem:M,selectItem:N,handleEnter:()=>{let e=!l.value.trim()&&y.value.length>0,t=l.value.trim()&&_.value.length>0;if(e){let e=y.value[u.value];e&&M(e)}else if(t){let e=_.value[u.value];e&&N(e)}},focusNext:()=>{let e=l.value.trim()?_.value.length-1:y.value.length-1;u.value=Math.min(u.value+1,e)},focusPrev:()=>{u.value=Math.max(u.value-1,0)}}}const A={class:`robot-search-palette`},j={class:`robot-search-header`},M=[`placeholder`],N={class:`robot-search-content`},ee={key:0,class:`robot-empty-state`},te={class:`robot-search-results`},P={class:`robot-result-group`},ne={class:`robot-group-title`},re={class:`robot-group-count`},ie={class:`robot-group-items`},ae=[`onClick`,`onMouseenter`],oe={key:1,class:`robot-item-icon robot-default-icon`},se={class:`robot-item-content`},ce={class:`robot-item-label`},le={class:`robot-item-desc`},ue=[`onClick`],de={class:`robot-search-results`},F={key:0,class:`robot-empty-state`},I={class:`robot-result-group`},L={class:`robot-group-title`},R={class:`robot-group-count`},z={class:`robot-group-items`},B=[`onClick`,`onMouseenter`],V={key:1,class:`robot-item-icon robot-default-icon`},fe={class:`robot-item-content`},H=[`innerHTML`],pe={class:`robot-item-desc`},me={key:2,class:`robot-item-badge`},he={class:`robot-search-footer`},ge={key:0,class:`robot-footer-info`},_e={key:0},ve={key:1};var U=e(d({name:`C_GlobalSearch`,__name:`index`,props:{options:{},placeholder:{default:`搜索导航菜单...`},emptyText:{default:`输入关键词搜索菜单`},resultGroupTitle:{default:`菜单导航`}},setup(e,{expose:i}){let{showDialog:d,searchValue:p,selectedIndex:h,searchInputRef:g,isDark:v,filteredMenuItems:w,displayHistory:U,hasResults:W,hasContent:G,getItemClasses:K,highlightMatch:ye,formatMenuPath:q,clearHistory:J,removeHistoryItem:be,openDialog:Y,closeDialog:X,selectHistoryItem:xe,selectItem:Se,handleEnter:Z,focusNext:Q,focusPrev:$}=k(e.options);return i({openDialog:Y,closeDialog:X}),(e,i)=>(_(),s(`div`,A,[o(` 搜索触发按钮 `),c(`div`,{class:m([`robot-search-trigger`,{"trigger-dark":S(v)}]),onClick:i[0]||=(...e)=>S(Y)&&S(Y)(...e)},i[11]||=[c(`div`,{class:`i-mdi:search robot-trigger-icon`},null,-1),c(`span`,{class:`robot-trigger-text`},`搜索`,-1),c(`span`,{class:`robot-trigger-shortcut`},`Ctrl K`,-1)],2),o(` 搜索对话框 `),(_(),a(n,{to:`body`},[u(r,{name:`robot-dialog`},{default:T(()=>[S(d)?(_(),s(`div`,{key:0,class:`robot-dialog-overlay`,onClick:i[9]||=(...e)=>S(X)&&S(X)(...e),onKeydown:i[10]||=D((...e)=>S(X)&&S(X)(...e),[`esc`])},[c(`div`,{class:m([`robot-dialog-container`,{"dialog-dark":S(v)}]),onClick:i[8]||=O(()=>{},[`stop`])},[o(` 搜索头部 `),c(`div`,j,[i[13]||=c(`div`,{class:`i-mdi:magnify robot-search-icon`},null,-1),E(c(`input`,{ref_key:`searchInputRef`,ref:g,"onUpdate:modelValue":i[1]||=e=>f(p)?p.value=e:null,type:`text`,placeholder:e.placeholder,class:`robot-search-input`,onKeydown:[i[2]||=D((...e)=>S(X)&&S(X)(...e),[`esc`]),i[3]||=D((...e)=>S(Z)&&S(Z)(...e),[`enter`]),i[4]||=D((...e)=>S(Q)&&S(Q)(...e),[`arrow-down`]),i[5]||=D((...e)=>S($)&&S($)(...e),[`arrow-up`])]},null,40,M),[[C,S(p)]]),c(`button`,{class:`robot-close-btn`,onClick:i[6]||=(...e)=>S(X)&&S(X)(...e)},i[12]||=[c(`div`,{class:`i-mdi:close`},null,-1)])]),o(` 搜索内容 `),c(`div`,N,[o(` 空状态 `),S(G)?!S(p).trim()&&S(U).length>0?(_(),s(t,{key:1},[o(` 搜索历史 `),c(`div`,te,[c(`div`,P,[c(`div`,ne,[i[16]||=c(`div`,{class:`i-mdi:clock-time-four-outline robot-group-icon`},null,-1),i[17]||=l(` 最近搜索 `,-1),c(`span`,re,x(S(U).length),1),c(`button`,{class:`robot-clear-history`,onClick:i[7]||=(...e)=>S(J)&&S(J)(...e),title:`清空历史`},i[15]||=[c(`div`,{class:`i-mdi:delete-outline`},null,-1)])]),c(`div`,ie,[(_(!0),s(t,null,y(S(U),(e,t)=>(_(),s(`div`,{key:`history-${t}`,class:m(S(K)(t,!0)),onClick:t=>S(xe)(e),onMouseenter:e=>h.value=t},[e.menuItem?.icon?(_(),a(b(e.menuItem.icon),{key:0,class:`robot-item-icon`})):(_(),s(`div`,oe,i[18]||=[c(`div`,{class:`i-mdi:file-document-outline`},null,-1)])),c(`div`,se,[c(`div`,ce,x(e.query),1),c(`div`,le,x(S(q)(e.menuItem?.key||``)),1)]),c(`button`,{class:`robot-history-delete`,onClick:O(e=>S(be)(t),[`stop`]),title:`删除此记录`},i[19]||=[c(`div`,{class:`i-mdi:close`},null,-1)],8,ue)],42,ae))),128))])])])],64)):S(p).trim()?(_(),s(t,{key:2},[o(` 搜索结果 `),c(`div`,de,[o(` 无结果状态 `),S(W)?(_(),s(t,{key:1},[o(` 搜索结果列表 `),c(`div`,I,[c(`div`,L,[i[21]||=c(`div`,{class:`i-mdi:menu robot-group-icon`},null,-1),l(` `+x(e.resultGroupTitle)+` `,1),c(`span`,R,x(S(w).length),1)]),c(`div`,z,[(_(!0),s(t,null,y(S(w),(e,t)=>(_(),s(`div`,{key:e.key,class:m(S(K)(t,!1)),onClick:t=>S(Se)(e),onMouseenter:e=>h.value=t},[e.icon?(_(),a(b(e.icon),{key:0,class:`robot-item-icon`})):(_(),s(`div`,V,i[22]||=[c(`div`,{class:`i-mdi:file-document-outline`},null,-1)])),c(`div`,fe,[c(`div`,{class:`robot-item-label`,innerHTML:S(ye)(e.label,S(p))},null,8,H),c(`div`,pe,x(S(q)(e.key)),1)]),e.children?.length?(_(),s(`div`,me,x(e.children.length),1)):o(`v-if`,!0)],42,B))),128))])])],2112)):(_(),s(`div`,F,[i[20]||=c(`div`,{class:`i-mdi:magnify robot-empty-icon`},null,-1),c(`p`,null,`未找到 "`+x(S(p))+`" 相关内容`,1)]))])],64)):o(`v-if`,!0):(_(),s(`div`,ee,[i[14]||=c(`div`,{class:`i-mdi:magnify robot-empty-icon`},null,-1),c(`p`,null,x(e.emptyText),1)]))]),o(` 搜索底部 `),c(`div`,he,[i[23]||=c(`div`,{class:`robot-footer-actions`},[c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`↵`),c(`span`,null,`选择`)]),c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`↑↓`),c(`span`,null,`导航`)]),c(`div`,{class:`robot-action-item`},[c(`kbd`,null,`esc`),c(`span`,null,`关闭`)])],-1),S(G)?(_(),s(`div`,ge,[S(p).trim()&&S(W)?(_(),s(`span`,_e,` 共 `+x(S(w).length)+` 项结果 `,1)):!S(p).trim()&&S(U).length>0?(_(),s(`span`,ve,x(S(U).length)+` 条历史记录 `,1)):o(`v-if`,!0)])):o(`v-if`,!0)])],2)],32)):o(`v-if`,!0)]),_:1})]))]))}}),[[`__scopeId`,`data-v-0c844dfd`]]);export{k as n,U as t};
|
|
2
2
|
//# sourceMappingURL=C_GlobalSearch2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_GlobalSearch2.js","names":[],"sources":["../src/components/C_GlobalSearch/composables/useGlobalSearch.ts","../src/components/C_GlobalSearch/index.vue"],"sourcesContent":["import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\nimport type { SearchMenuItem, HistoryItem, GlobalSearchOptions } from '../types'\n\n/**\n * 全局搜索逻辑 — 管理菜单搜索、历史记录、键盘导航\n *\n * 已解耦:不依赖任何项目级 store / router,\n * 所有外部数据通过 options 注入。\n */\nexport function useGlobalSearch(options: GlobalSearchOptions) {\n const {\n menuItems: getMenuItems,\n isDark: getIsDark,\n onSelect,\n storageKey = 'robot-search-history',\n maxHistory = 10,\n maxDisplayHistory = 5,\n } = options\n\n // ==================== 响应式状态 ====================\n const showDialog = ref(false)\n const searchValue = ref('')\n const selectedIndex = ref(0)\n const searchInputRef = ref<HTMLInputElement>()\n const searchHistory = ref<HistoryItem[]>([])\n\n // ==================== 计算属性 ====================\n const isDark = computed(() => getIsDark?.() ?? false)\n\n const filteredMenuItems = computed(() => {\n if (!searchValue.value.trim()) return []\n const query = searchValue.value.toLowerCase()\n const items = getMenuItems()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n formatMenuPath(item.key).toLowerCase().includes(query)\n )\n })\n\n const displayHistory = computed(() =>\n searchHistory.value.slice(0, maxDisplayHistory)\n )\n const hasResults = computed(() => filteredMenuItems.value.length > 0)\n const hasContent = computed(\n () => hasResults.value || displayHistory.value.length > 0\n )\n\n // ==================== 工具函数 ====================\n const getItemClasses = (index: number, isHistory: boolean) => [\n 'robot-result-item',\n isHistory && 'robot-history-item',\n { 'robot-result-item-selected': selectedIndex.value === index },\n ]\n\n const highlightMatch = (text: string, search: string): string => {\n if (!search) return text\n const regex = new RegExp(\n `(${search.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n 'gi'\n )\n return text.replace(regex, '<mark class=\"robot-highlight\">$1</mark>')\n }\n\n const formatMenuPath = (key: string): string =>\n key.replace(/^\\//, '').replace(/\\//g, ' > ') || '首页'\n\n // ==================== 搜索历史管理 ====================\n const addToHistory = (menuItem: SearchMenuItem) => {\n if (!menuItem.label.trim()) return\n const query = menuItem.label\n const filtered = searchHistory.value.filter(\n (item: HistoryItem) =>\n !(item.query === query && item.menuItem?.key === menuItem.key)\n )\n searchHistory.value = [\n { query, menuItem, timestamp: Date.now() },\n ...filtered,\n ].slice(0, maxHistory)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n }\n\n const loadHistory = () => {\n try {\n const saved = localStorage.getItem(storageKey)\n if (saved) {\n const parsed = JSON.parse(saved)\n searchHistory.value = parsed.map((item: any) =>\n typeof item === 'string'\n ? { query: item, menuItem: null, timestamp: 0 }\n : item\n )\n }\n } catch (error) {\n console.error('加载搜索历史失败:', error)\n }\n }\n\n const clearHistory = () => {\n searchHistory.value = []\n localStorage.removeItem(storageKey)\n }\n\n const removeHistoryItem = (index: number) => {\n searchHistory.value.splice(index, 1)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n if (selectedIndex.value >= searchHistory.value.length) {\n selectedIndex.value = Math.max(0, searchHistory.value.length - 1)\n }\n }\n\n // ==================== 对话框控制 ====================\n const openDialog = async () => {\n showDialog.value = true\n searchValue.value = ''\n selectedIndex.value = 0\n await nextTick()\n searchInputRef.value?.focus()\n }\n\n const closeDialog = () => {\n showDialog.value = false\n searchValue.value = ''\n selectedIndex.value = 0\n }\n\n // ==================== 选择项目 ====================\n const selectHistoryItem = (historyItem: HistoryItem) => {\n if (historyItem.menuItem) {\n const hasChildren = !!historyItem.menuItem.children?.length\n onSelect?.(historyItem.menuItem.key, hasChildren)\n closeDialog()\n } else {\n searchValue.value = historyItem.query\n selectedIndex.value = 0\n }\n }\n\n const selectItem = (item: SearchMenuItem) => {\n addToHistory(item)\n const hasChildren = !!item.children?.length\n onSelect?.(item.key, hasChildren)\n closeDialog()\n }\n\n // ==================== 键盘导航 ====================\n const handleEnter = () => {\n const isHistoryMode =\n !searchValue.value.trim() && displayHistory.value.length > 0\n const isSearchMode =\n searchValue.value.trim() && filteredMenuItems.value.length > 0\n\n if (isHistoryMode) {\n const historyItem = displayHistory.value[selectedIndex.value]\n if (historyItem) selectHistoryItem(historyItem)\n } else if (isSearchMode) {\n const item = filteredMenuItems.value[selectedIndex.value]\n if (item) selectItem(item)\n }\n }\n\n const focusNext = () => {\n const maxIndex = !searchValue.value.trim()\n ? displayHistory.value.length - 1\n : filteredMenuItems.value.length - 1\n selectedIndex.value = Math.min(selectedIndex.value + 1, maxIndex)\n }\n\n const focusPrev = () => {\n selectedIndex.value = Math.max(selectedIndex.value - 1, 0)\n }\n\n // ==================== 监听器和生命周期 ====================\n watch(searchValue, () => {\n selectedIndex.value = 0\n })\n\n onMounted(() => {\n loadHistory()\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n e.preventDefault()\n openDialog()\n }\n }\n document.addEventListener('keydown', handleKeydown)\n onUnmounted(() => document.removeEventListener('keydown', handleKeydown))\n })\n\n return {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n }\n}\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"qhBASA,SAAgB,EAAgB,EAA8B,CAC5D,GAAM,CACJ,UAAW,EACX,OAAQ,EACR,WACA,aAAa,uBACb,aAAa,GACb,oBAAoB,GAClB,EAGE,EAAa,EAAI,GAAM,CACvB,EAAc,EAAI,GAAG,CACrB,EAAgB,EAAI,EAAE,CACtB,EAAiB,GAAuB,CACxC,EAAgB,EAAmB,EAAE,CAAC,CAGtC,EAAS,MAAe,KAAa,EAAI,GAAM,CAE/C,EAAoB,MAAe,CACvC,GAAI,CAAC,EAAY,MAAM,MAAM,CAAE,MAAO,EAAE,CACxC,IAAM,EAAQ,EAAY,MAAM,aAAa,CAE7C,OADc,GAAc,CACf,OACX,GACE,EAAK,MAAM,aAAa,CAAC,SAAS,EAAM,EACxC,EAAe,EAAK,IAAI,CAAC,aAAa,CAAC,SAAS,EAAM,CACzD,EACD,CAEI,EAAiB,MACrB,EAAc,MAAM,MAAM,EAAG,EAAkB,CAChD,CACK,EAAa,MAAe,EAAkB,MAAM,OAAS,EAAE,CAC/D,EAAa,MACX,EAAW,OAAS,EAAe,MAAM,OAAS,EACzD,CAGK,GAAkB,EAAe,IAAuB,CAC5D,oBACA,GAAa,qBACb,CAAE,6BAA8B,EAAc,QAAU,EAAO,CAChE,CAEK,GAAkB,EAAc,IAA2B,CAC/D,GAAI,CAAC,EAAQ,OAAO,EACpB,IAAM,EAAY,OAChB,IAAI,EAAO,QAAQ,sBAAuB,OAAO,CAAC,GAClD,KACD,CACD,OAAO,EAAK,QAAQ,EAAO,0CAA0C,EAGjE,EAAkB,GACtB,EAAI,QAAQ,MAAO,GAAG,CAAC,QAAQ,MAAO,MAAM,EAAI,KAG5C,EAAgB,GAA6B,CACjD,GAAI,CAAC,EAAS,MAAM,MAAM,CAAE,OAC5B,IAAM,EAAQ,EAAS,MACjB,EAAW,EAAc,MAAM,OAClC,GACC,EAAE,EAAK,QAAU,GAAS,EAAK,UAAU,MAAQ,EAAS,KAC7D,CACD,EAAc,MAAQ,CACpB,CAAE,QAAO,WAAU,UAAW,KAAK,KAAK,CAAE,CAC1C,GAAG,EACJ,CAAC,MAAM,EAAG,EAAW,CACtB,aAAa,QAAQ,EAAY,KAAK,UAAU,EAAc,MAAM,CAAC,EAGjE,MAAoB,CACxB,GAAI,CACF,IAAM,EAAQ,aAAa,QAAQ,EAAW,CAC1C,IAEF,EAAc,MADC,KAAK,MAAM,EAAM,CACH,IAAK,GAChC,OAAO,GAAS,SACZ,CAAE,MAAO,EAAM,SAAU,KAAM,UAAW,EAAG,CAC7C,EACL,QAEI,EAAO,CACd,QAAQ,MAAM,YAAa,EAAM,GAI/B,MAAqB,CACzB,EAAc,MAAQ,EAAE,CACxB,aAAa,WAAW,EAAW,EAG/B,EAAqB,GAAkB,CAC3C,EAAc,MAAM,OAAO,EAAO,EAAE,CACpC,aAAa,QAAQ,EAAY,KAAK,UAAU,EAAc,MAAM,CAAC,CACjE,EAAc,OAAS,EAAc,MAAM,SAC7C,EAAc,MAAQ,KAAK,IAAI,EAAG,EAAc,MAAM,OAAS,EAAE,GAK/D,EAAa,SAAY,CAC7B,EAAW,MAAQ,GACnB,EAAY,MAAQ,GACpB,EAAc,MAAQ,EACtB,MAAM,GAAU,CAChB,EAAe,OAAO,OAAO,EAGzB,MAAoB,CACxB,EAAW,MAAQ,GACnB,EAAY,MAAQ,GACpB,EAAc,MAAQ,GAIlB,EAAqB,GAA6B,CACtD,GAAI,EAAY,SAAU,CACxB,IAAM,EAAc,CAAC,CAAC,EAAY,SAAS,UAAU,OACrD,IAAW,EAAY,SAAS,IAAK,EAAY,CACjD,GAAa,MAEb,EAAY,MAAQ,EAAY,MAChC,EAAc,MAAQ,GAIpB,EAAc,GAAyB,CAC3C,EAAa,EAAK,CAClB,IAAM,EAAc,CAAC,CAAC,EAAK,UAAU,OACrC,IAAW,EAAK,IAAK,EAAY,CACjC,GAAa,EA+Cf,OAhBA,EAAM,MAAmB,CACvB,EAAc,MAAQ,GACtB,CAEF,MAAgB,CACd,GAAa,CACb,IAAM,EAAiB,GAAqB,EACrC,EAAE,SAAW,EAAE,UAAY,EAAE,MAAQ,MACxC,EAAE,gBAAgB,CAClB,GAAY,GAGhB,SAAS,iBAAiB,UAAW,EAAc,CACnD,MAAkB,SAAS,oBAAoB,UAAW,EAAc,CAAC,EACzE,CAEK,CACL,aACA,cACA,gBACA,iBACA,SACA,oBACA,iBACA,aACA,aACA,iBACA,iBACA,iBACA,eACA,oBACA,aACA,cACA,oBACA,aACA,gBA9DwB,CACxB,IAAM,EACJ,CAAC,EAAY,MAAM,MAAM,EAAI,EAAe,MAAM,OAAS,EACvD,EACJ,EAAY,MAAM,MAAM,EAAI,EAAkB,MAAM,OAAS,EAE/D,GAAI,EAAe,CACjB,IAAM,EAAc,EAAe,MAAM,EAAc,OACnD,GAAa,EAAkB,EAAY,SACtC,EAAc,CACvB,IAAM,EAAO,EAAkB,MAAM,EAAc,OAC/C,GAAM,EAAW,EAAK,GAoD5B,cAhDsB,CACtB,IAAM,EAAY,EAAY,MAAM,MAAM,CAEtC,EAAkB,MAAM,OAAS,EADjC,EAAe,MAAM,OAAS,EAElC,EAAc,MAAQ,KAAK,IAAI,EAAc,MAAQ,EAAG,EAAS,EA6CjE,cA1CsB,CACtB,EAAc,MAAQ,KAAK,IAAI,EAAc,MAAQ,EAAG,EAAE,EA0C3D,qpCCwCD,GAAM,CACJ,aACA,cACA,gBACA,iBACA,SACA,oBACA,iBACA,aACA,aACA,iBACA,kBACA,iBACA,eACA,qBACA,aACA,cACA,qBACA,cACA,cACA,YACA,aACE,EA5BU,EA4BY,QAAO,QAEjC,EAAa,CAAE,aAAY,cAAa,CAAA,aA7QxC,EA2NK,MA3NL,EA2NK,CA1NH,EAAA,WAAc,CACd,EAQK,MAAA,CAPH,MAAK,EAAA,CAAC,uBAAqB,CAAA,eACD,EAAA,EAAM,CAAA,CAAA,CAAA,CAC/B,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAU,WAElB,EAA8C,MAAA,CAAzC,MAAM,kCAAiC,CAAA,KAAA,GAAA,CAC5C,EAAyC,OAAA,CAAnC,MAAM,qBAAoB,CAAC,KAAE,GAAA,CACnC,EAAiD,OAAA,CAA3C,MAAM,yBAAwB,CAAC,SAAM,GAAA,KAG7C,EAAA,UAAa,MACb,EA6MU,EAAA,CA7MA,GAAG,OAAM,CAAA,CACjB,EA2MY,EAAA,CA3MA,KAAK,eAAc,CAAA,eA6MpC,CA3Me,EAAA,EAAU,EAAA,GAAA,CADlB,EAyMK,MAAA,OAvMH,MAAM,uBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAClB,UAAO,AAAA,EAAA,MAAA,GAAA,GAAA,IAAM,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,MAAA,CAAA,GAEzB,EAkMK,MAAA,CAjMH,MAAK,EAAA,CAAC,yBAAuB,CAAA,cACJ,EAAA,EAAM,CAAA,CAAA,CAAA,CAC9B,QAAK,AAAA,EAAA,KAAA,MAAN,GAAO,CAAA,OAAA,CAAA,GAEP,EAAA,SAAY,CACZ,EAmBK,MAnBL,EAmBK,SAlBH,EAA8C,MAAA,CAAzC,MAAM,kCAAiC,CAAA,KAAA,GAAA,GAC5C,EAUC,QAAA,SATK,iBAAJ,IAAI,uCACK,EAAW,MAAA,EAAA,KACpB,KAAK,OACJ,YAAa,EAAA,YACd,MAAM,qBACL,UAAO,kBAAM,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,MAAA,CAAA,kBACT,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,QAAA,CAAA,kBACN,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAS,CAAA,CAAA,aAAA,CAAA,kBACX,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAS,CAAA,CAAA,WAAA,CAAA,kBAPnB,EAAA,EAAW,CAAA,CAAA,CAAA,CAStB,EAKQ,SAAA,CAJN,MAAM,kBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,WAEnB,EAA0B,MAAA,CAArB,MAAM,cAAa,CAAA,KAAA,GAAA,CAAA,CAAA,GAI5B,EAAA,SAAY,CACZ,EAyIK,MAzIL,EAyIK,CAxIH,EAAA,QAAW,CAEF,EAAA,EAAU,CAIF,CAKH,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAc,CAAC,OAAM,GAAA,GAAA,CADzD,EA6DU,EAAA,CAAA,IAAA,EAAA,CAAA,CA9DV,EAAA,SAAY,CAIV,EAyDK,MAzDL,GAyDK,CAxDH,EAuDK,MAvDL,EAuDK,CAtDH,EAeK,MAfL,GAeK,SAdH,EAEC,MAAA,CADC,MAAM,iDAA+C,CAAA,KAAA,GAAA,WACtD,SAED,GAAA,CAAA,EAEQ,OAFR,GAEQ,EADN,EAAA,EAAc,CAAC,OAAA,CAAA,EAAA,CAEjB,EAMQ,SAAA,CALN,MAAM,sBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAY,CACpB,MAAM,iBAEN,EAAmC,MAAA,CAA9B,MAAM,uBAAsB,CAAA,KAAA,GAAA,CAAA,CAAA,GAGrC,EAqCK,MArCL,GAqCK,EAAA,EAAA,GAAA,CApCH,EAmCK,EAAA,KAAA,EAlC4B,EAAA,EAAc,EAArC,EAAa,SADvB,EAmCK,MAAA,CAjCF,IAAG,WAAa,IAChB,MAAK,EAAE,EAAA,EAAc,CAAC,EAAK,GAAA,CAAA,CAC3B,QAAK,GAAE,EAAA,GAAiB,CAAC,EAAW,CACpC,aAAU,GAAE,EAAA,MAAgB,IAGrB,EAAY,UAAU,MAAA,GAAA,CAD9B,EAIC,EAFM,EAAY,SAAS,KAAI,CAAA,OAC9B,MAAM,0BAER,EAKK,MALL,GAKK,AAAA,EAAA,MAAA,CADH,EAA0C,MAAA,CAArC,MAAM,8BAA6B,CAAA,KAAA,GAAA,CAAA,CAAA,EAE1C,EASK,MATL,GASK,CARH,EAEK,MAFL,GAEK,EADA,EAAY,MAAK,CAAA,EAAA,CAEtB,EAIK,MAJL,GAIK,EAFD,EAAA,EAAc,CAAC,EAAY,UAAU,KAAG,GAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAI9C,EAMQ,SAAA,CALN,MAAM,uBACL,QAAK,EAAA,GAAO,EAAA,GAAiB,CAAC,EAAK,CAAA,CAAA,OAAA,CAAA,CACpC,MAAM,kBAEN,EAA0B,MAAA,CAArB,MAAM,cAAa,CAAA,KAAA,GAAA,CAAA,CAAA,EAAA,GAAA,6BASf,EAAA,EAAW,CAAC,MAAI,EAAA,GAAA,CAArC,EA6DU,EAAA,CAAA,IAAA,EAAA,CAAA,CA9DV,EAAA,SAAY,CAEV,EA2DK,MA3DL,GA2DK,CA1DH,EAAA,UAAa,CAEJ,EAAA,EAAU,EAIc,GAAA,CAIjC,EA+CK,EAAA,CAAA,IAAA,EAAA,CAAA,CAhDL,EAAA,WAAc,CACd,EA+CK,MA/CL,EA+CK,CA3CH,EAMK,MANL,EAMK,SALH,EAA0C,MAAA,CAArC,MAAM,8BAA6B,CAAA,KAAA,GAAA,GAAE,IAC1C,EAAG,EAAA,iBAAgB,CAAE,IACrB,EAAA,CAAA,EAEQ,OAFR,EAEQ,EADN,EAAA,EAAiB,CAAC,OAAA,CAAA,EAAA,GAGtB,EAmCK,MAnCL,EAmCK,EAAA,EAAA,GAAA,CAlCH,EAiCK,EAAA,KAAA,EAhCqB,EAAA,EAAiB,EAAjC,EAAM,SADhB,EAiCK,MAAA,CA/BF,IAAK,EAAK,IACV,MAAK,EAAE,EAAA,EAAc,CAAC,EAAK,GAAA,CAAA,CAC3B,QAAK,GAAE,EAAA,GAAU,CAAC,EAAI,CACtB,aAAU,GAAE,EAAA,MAAgB,IAGrB,EAAK,MAAA,GAAA,CADb,EAIC,EAFM,EAAK,KAAI,CAAA,OACd,MAAM,0BAER,EAKK,MALL,EAKK,AAAA,EAAA,MAAA,CADH,EAA0C,MAAA,CAArC,MAAM,8BAA6B,CAAA,KAAA,GAAA,CAAA,CAAA,EAE1C,EAQK,MARL,GAQK,CAPH,EAGM,MAAA,CAFJ,MAAM,mBACN,UAAQ,EAAA,GAAc,CAAC,EAAK,MAAO,EAAA,EAAW,CAAA,YAEhD,EAEK,MAFL,GAEK,EADA,EAAA,EAAc,CAAC,EAAK,IAAG,CAAA,CAAA,EAAA,CAAA,CAAA,CAItB,EAAK,UAAU,QAAA,GAAA,CADvB,EAKK,MALL,GAKK,EADA,EAAK,SAAS,OAAM,CAAA,EAAA,EAAA,EAAA,OAAA,GAAA,6BAnDZ,GAAA,CADnB,EAMK,MANL,EAMK,CAAA,AAAA,EAAA,MAFH,EAA6C,MAAA,CAAxC,MAAM,iCAAgC,CAAA,KAAA,GAAA,CAC3C,EAAkC,IAAA,KAA/B,QAAK,EAAG,EAAA,EAAW,CAAA,CAAG,SAAM,EAAA,CAAA,CAAA,wBAhFlB,GAAA,CADnB,EAMK,MANL,GAMK,CAAA,AAAA,EAAA,MAFH,EAA6C,MAAA,CAAxC,MAAM,iCAAgC,CAAA,KAAA,GAAA,CAC3C,EAAqB,IAAA,KAAA,EAAf,EAAA,UAAS,CAAA,EAAA,CAAA,CAAA,IAoInB,EAAA,SAAY,CACZ,EAyBK,MAzBL,GAyBK,CAAA,AAAA,EAAA,MAxBH,EAUK,MAAA,CAVA,MAAM,uBAAsB,CAAA,CAC/B,EAEK,MAAA,CAFA,MAAM,oBAAmB,CAAA,CAC5B,EAAY,MAAA,KAAP,IAAC,CAAM,EAAc,OAAA,KAAR,KAAE,CAAA,CAAA,CAEtB,EAEK,MAAA,CAFA,MAAM,oBAAmB,CAAA,CAC5B,EAAa,MAAA,KAAR,KAAE,CAAM,EAAc,OAAA,KAAR,KAAE,CAAA,CAAA,CAEvB,EAEK,MAAA,CAFA,MAAM,oBAAmB,CAAA,CAC5B,EAAc,MAAA,KAAT,MAAG,CAAM,EAAc,OAAA,KAAR,KAAE,CAAA,CAAA,MAIlB,EAAA,EAAU,EAAA,GAAA,CADlB,EAYK,MAZL,GAYK,CARS,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAU,EAAA,GAAA,CAA5C,EAEM,OAAA,GAFuC,MACzC,EAAG,EAAA,EAAiB,CAAC,OAAM,CAAG,QAClC,EAAA,EAAA,CAEc,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAc,CAAC,OAAM,GAAA,GAAA,CADzD,EAIM,OAAA,GAAA,EADD,EAAA,EAAc,CAAC,OAAM,CAAG,UAC7B,EAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"C_GlobalSearch2.js","names":["placeholder","emptyText","resultGroupTitle"],"sources":["../src/components/C_GlobalSearch/composables/useGlobalSearch.ts","../src/components/C_GlobalSearch/index.vue","../src/components/C_GlobalSearch/index.vue"],"sourcesContent":["import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'\nimport type { SearchMenuItem, HistoryItem, GlobalSearchOptions } from '../types'\n\n/**\n * 全局搜索逻辑 — 管理菜单搜索、历史记录、键盘导航\n *\n * 已解耦:不依赖任何项目级 store / router,\n * 所有外部数据通过 options 注入。\n */\nexport function useGlobalSearch(options: GlobalSearchOptions) {\n const {\n menuItems: getMenuItems,\n isDark: getIsDark,\n onSelect,\n storageKey = 'robot-search-history',\n maxHistory = 10,\n maxDisplayHistory = 5,\n } = options\n\n // ==================== 响应式状态 ====================\n const showDialog = ref(false)\n const searchValue = ref('')\n const selectedIndex = ref(0)\n const searchInputRef = ref<HTMLInputElement>()\n const searchHistory = ref<HistoryItem[]>([])\n\n // ==================== 计算属性 ====================\n const isDark = computed(() => getIsDark?.() ?? false)\n\n const filteredMenuItems = computed(() => {\n if (!searchValue.value.trim()) return []\n const query = searchValue.value.toLowerCase()\n const items = getMenuItems()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n formatMenuPath(item.key).toLowerCase().includes(query)\n )\n })\n\n const displayHistory = computed(() =>\n searchHistory.value.slice(0, maxDisplayHistory)\n )\n const hasResults = computed(() => filteredMenuItems.value.length > 0)\n const hasContent = computed(\n () => hasResults.value || displayHistory.value.length > 0\n )\n\n // ==================== 工具函数 ====================\n const getItemClasses = (index: number, isHistory: boolean) => [\n 'robot-result-item',\n isHistory && 'robot-history-item',\n { 'robot-result-item-selected': selectedIndex.value === index },\n ]\n\n const highlightMatch = (text: string, search: string): string => {\n if (!search) return text\n const regex = new RegExp(\n `(${search.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n 'gi'\n )\n return text.replace(regex, '<mark class=\"robot-highlight\">$1</mark>')\n }\n\n const formatMenuPath = (key: string): string =>\n key.replace(/^\\//, '').replace(/\\//g, ' > ') || '首页'\n\n // ==================== 搜索历史管理 ====================\n const addToHistory = (menuItem: SearchMenuItem) => {\n if (!menuItem.label.trim()) return\n const query = menuItem.label\n const filtered = searchHistory.value.filter(\n (item: HistoryItem) =>\n !(item.query === query && item.menuItem?.key === menuItem.key)\n )\n searchHistory.value = [\n { query, menuItem, timestamp: Date.now() },\n ...filtered,\n ].slice(0, maxHistory)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n }\n\n const loadHistory = () => {\n try {\n const saved = localStorage.getItem(storageKey)\n if (saved) {\n const parsed = JSON.parse(saved)\n searchHistory.value = parsed.map((item: any) =>\n typeof item === 'string'\n ? { query: item, menuItem: null, timestamp: 0 }\n : item\n )\n }\n } catch (error) {\n console.error('加载搜索历史失败:', error)\n }\n }\n\n const clearHistory = () => {\n searchHistory.value = []\n localStorage.removeItem(storageKey)\n }\n\n const removeHistoryItem = (index: number) => {\n searchHistory.value.splice(index, 1)\n localStorage.setItem(storageKey, JSON.stringify(searchHistory.value))\n if (selectedIndex.value >= searchHistory.value.length) {\n selectedIndex.value = Math.max(0, searchHistory.value.length - 1)\n }\n }\n\n // ==================== 对话框控制 ====================\n const openDialog = async () => {\n showDialog.value = true\n searchValue.value = ''\n selectedIndex.value = 0\n await nextTick()\n searchInputRef.value?.focus()\n }\n\n const closeDialog = () => {\n showDialog.value = false\n searchValue.value = ''\n selectedIndex.value = 0\n }\n\n // ==================== 选择项目 ====================\n const selectHistoryItem = (historyItem: HistoryItem) => {\n if (historyItem.menuItem) {\n const hasChildren = !!historyItem.menuItem.children?.length\n onSelect?.(historyItem.menuItem.key, hasChildren)\n closeDialog()\n } else {\n searchValue.value = historyItem.query\n selectedIndex.value = 0\n }\n }\n\n const selectItem = (item: SearchMenuItem) => {\n addToHistory(item)\n const hasChildren = !!item.children?.length\n onSelect?.(item.key, hasChildren)\n closeDialog()\n }\n\n // ==================== 键盘导航 ====================\n const handleEnter = () => {\n const isHistoryMode =\n !searchValue.value.trim() && displayHistory.value.length > 0\n const isSearchMode =\n searchValue.value.trim() && filteredMenuItems.value.length > 0\n\n if (isHistoryMode) {\n const historyItem = displayHistory.value[selectedIndex.value]\n if (historyItem) selectHistoryItem(historyItem)\n } else if (isSearchMode) {\n const item = filteredMenuItems.value[selectedIndex.value]\n if (item) selectItem(item)\n }\n }\n\n const focusNext = () => {\n const maxIndex = !searchValue.value.trim()\n ? displayHistory.value.length - 1\n : filteredMenuItems.value.length - 1\n selectedIndex.value = Math.min(selectedIndex.value + 1, maxIndex)\n }\n\n const focusPrev = () => {\n selectedIndex.value = Math.max(selectedIndex.value - 1, 0)\n }\n\n // ==================== 监听器和生命周期 ====================\n watch(searchValue, () => {\n selectedIndex.value = 0\n })\n\n onMounted(() => {\n loadHistory()\n const handleKeydown = (e: KeyboardEvent) => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n e.preventDefault()\n openDialog()\n }\n }\n document.addEventListener('keydown', handleKeydown)\n onUnmounted(() => document.removeEventListener('keydown', handleKeydown))\n })\n\n return {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n }\n}\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Description: 全局搜索组件 - 命令面板式搜索\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"robot-search-palette\">\n <!-- 搜索触发按钮 -->\n <div\n class=\"robot-search-trigger\"\n :class=\"{ 'trigger-dark': isDark }\"\n @click=\"openDialog\"\n >\n <div class=\"i-mdi:search robot-trigger-icon\" />\n <span class=\"robot-trigger-text\">搜索</span>\n <span class=\"robot-trigger-shortcut\">Ctrl K</span>\n </div>\n\n <!-- 搜索对话框 -->\n <Teleport to=\"body\">\n <Transition name=\"robot-dialog\">\n <div\n v-if=\"showDialog\"\n class=\"robot-dialog-overlay\"\n @click=\"closeDialog\"\n @keydown.esc=\"closeDialog\"\n >\n <div\n class=\"robot-dialog-container\"\n :class=\"{ 'dialog-dark': isDark }\"\n @click.stop\n >\n <!-- 搜索头部 -->\n <div class=\"robot-search-header\">\n <div class=\"i-mdi:magnify robot-search-icon\" />\n <input\n ref=\"searchInputRef\"\n v-model=\"searchValue\"\n type=\"text\"\n :placeholder=\"placeholder\"\n class=\"robot-search-input\"\n @keydown.esc=\"closeDialog\"\n @keydown.enter=\"handleEnter\"\n @keydown.arrow-down=\"focusNext\"\n @keydown.arrow-up=\"focusPrev\"\n />\n <button\n class=\"robot-close-btn\"\n @click=\"closeDialog\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n\n <!-- 搜索内容 -->\n <div class=\"robot-search-content\">\n <!-- 空状态 -->\n <div\n v-if=\"!hasContent\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>{{ emptyText }}</p>\n </div>\n\n <!-- 搜索历史 -->\n <template\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n <div class=\"robot-search-results\">\n <div class=\"robot-result-group\">\n <div class=\"robot-group-title\">\n <div\n class=\"i-mdi:clock-time-four-outline robot-group-icon\"\n />\n 最近搜索\n <span class=\"robot-group-count\">{{\n displayHistory.length\n }}</span>\n <button\n class=\"robot-clear-history\"\n @click=\"clearHistory\"\n title=\"清空历史\"\n >\n <div class=\"i-mdi:delete-outline\" />\n </button>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(historyItem, index) in displayHistory\"\n :key=\"`history-${index}`\"\n :class=\"getItemClasses(index, true)\"\n @click=\"selectHistoryItem(historyItem)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"historyItem.menuItem?.icon\"\n :is=\"historyItem.menuItem.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div class=\"robot-item-label\">\n {{ historyItem.query }}\n </div>\n <div class=\"robot-item-desc\">\n {{\n formatMenuPath(historyItem.menuItem?.key || '')\n }}\n </div>\n </div>\n <button\n class=\"robot-history-delete\"\n @click.stop=\"removeHistoryItem(index)\"\n title=\"删除此记录\"\n >\n <div class=\"i-mdi:close\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- 搜索结果 -->\n <template v-else-if=\"searchValue.trim()\">\n <div class=\"robot-search-results\">\n <!-- 无结果状态 -->\n <div\n v-if=\"!hasResults\"\n class=\"robot-empty-state\"\n >\n <div class=\"i-mdi:magnify robot-empty-icon\" />\n <p>未找到 \"{{ searchValue }}\" 相关内容</p>\n </div>\n\n <!-- 搜索结果列表 -->\n <div\n v-else\n class=\"robot-result-group\"\n >\n <div class=\"robot-group-title\">\n <div class=\"i-mdi:menu robot-group-icon\" />\n {{ resultGroupTitle }}\n <span class=\"robot-group-count\">{{\n filteredMenuItems.length\n }}</span>\n </div>\n <div class=\"robot-group-items\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.key\"\n :class=\"getItemClasses(index, false)\"\n @click=\"selectItem(item)\"\n @mouseenter=\"selectedIndex = index\"\n >\n <component\n v-if=\"item.icon\"\n :is=\"item.icon\"\n class=\"robot-item-icon\"\n />\n <div\n v-else\n class=\"robot-item-icon robot-default-icon\"\n >\n <div class=\"i-mdi:file-document-outline\" />\n </div>\n <div class=\"robot-item-content\">\n <div\n class=\"robot-item-label\"\n v-html=\"highlightMatch(item.label, searchValue)\"\n ></div>\n <div class=\"robot-item-desc\">\n {{ formatMenuPath(item.key) }}\n </div>\n </div>\n <div\n v-if=\"item.children?.length\"\n class=\"robot-item-badge\"\n >\n {{ item.children.length }}\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 搜索底部 -->\n <div class=\"robot-search-footer\">\n <div class=\"robot-footer-actions\">\n <div class=\"robot-action-item\">\n <kbd>↵</kbd><span>选择</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>↑↓</kbd><span>导航</span>\n </div>\n <div class=\"robot-action-item\">\n <kbd>esc</kbd><span>关闭</span>\n </div>\n </div>\n <div\n v-if=\"hasContent\"\n class=\"robot-footer-info\"\n >\n <span v-if=\"searchValue.trim() && hasResults\">\n 共 {{ filteredMenuItems.length }} 项结果\n </span>\n <span\n v-else-if=\"!searchValue.trim() && displayHistory.length > 0\"\n >\n {{ displayHistory.length }} 条历史记录\n </span>\n </div>\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { useGlobalSearch } from './composables/useGlobalSearch'\n import type { GlobalSearchOptions } from './types'\n\n defineOptions({ name: 'C_GlobalSearch' })\n\n interface Props {\n /** useGlobalSearch 配置(必须传入 menuItems + onSelect) */\n options: GlobalSearchOptions\n /** 搜索框 placeholder */\n placeholder?: string\n /** 无内容提示文字 */\n emptyText?: string\n /** 结果分组标题 */\n resultGroupTitle?: string\n }\n\n const props = withDefaults(defineProps<Props>(), {\n placeholder: '搜索导航菜单...',\n emptyText: '输入关键词搜索菜单',\n resultGroupTitle: '菜单导航',\n })\n\n const {\n showDialog,\n searchValue,\n selectedIndex,\n searchInputRef,\n isDark,\n filteredMenuItems,\n displayHistory,\n hasResults,\n hasContent,\n getItemClasses,\n highlightMatch,\n formatMenuPath,\n clearHistory,\n removeHistoryItem,\n openDialog,\n closeDialog,\n selectHistoryItem,\n selectItem,\n handleEnter,\n focusNext,\n focusPrev,\n } = useGlobalSearch(props.options)\n\n defineExpose({ openDialog, closeDialog })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"qhBASA,SAAgB,EAAgB,EAA8B,CAC5D,GAAM,CACJ,UAAW,EACX,OAAQ,EACR,WACA,aAAa,uBACb,aAAa,GACb,oBAAoB,GAClB,EAGE,EAAa,EAAI,GAAM,CACvB,EAAc,EAAI,GAAG,CACrB,EAAgB,EAAI,EAAE,CACtB,EAAiB,GAAuB,CACxC,EAAgB,EAAmB,EAAE,CAAC,CAGtC,EAAS,MAAe,KAAa,EAAI,GAAM,CAE/C,EAAoB,MAAe,CACvC,GAAI,CAAC,EAAY,MAAM,MAAM,CAAE,MAAO,EAAE,CACxC,IAAM,EAAQ,EAAY,MAAM,aAAa,CAE7C,OADc,GAAc,CACf,OACX,GACE,EAAK,MAAM,aAAa,CAAC,SAAS,EAAM,EACxC,EAAe,EAAK,IAAI,CAAC,aAAa,CAAC,SAAS,EAAM,CACzD,EACD,CAEI,EAAiB,MACrB,EAAc,MAAM,MAAM,EAAG,EAAkB,CAChD,CACK,EAAa,MAAe,EAAkB,MAAM,OAAS,EAAE,CAC/D,EAAa,MACX,EAAW,OAAS,EAAe,MAAM,OAAS,EACzD,CAGK,GAAkB,EAAe,IAAuB,CAC5D,oBACA,GAAa,qBACb,CAAE,6BAA8B,EAAc,QAAU,EAAO,CAChE,CAEK,GAAkB,EAAc,IAA2B,CAC/D,GAAI,CAAC,EAAQ,OAAO,EACpB,IAAM,EAAY,OAChB,IAAI,EAAO,QAAQ,sBAAuB,OAAO,CAAC,GAClD,KACD,CACD,OAAO,EAAK,QAAQ,EAAO,0CAA0C,EAGjE,EAAkB,GACtB,EAAI,QAAQ,MAAO,GAAG,CAAC,QAAQ,MAAO,MAAM,EAAI,KAG5C,EAAgB,GAA6B,CACjD,GAAI,CAAC,EAAS,MAAM,MAAM,CAAE,OAC5B,IAAM,EAAQ,EAAS,MACjB,EAAW,EAAc,MAAM,OAClC,GACC,EAAE,EAAK,QAAU,GAAS,EAAK,UAAU,MAAQ,EAAS,KAC7D,CACD,EAAc,MAAQ,CACpB,CAAE,QAAO,WAAU,UAAW,KAAK,KAAK,CAAE,CAC1C,GAAG,EACJ,CAAC,MAAM,EAAG,EAAW,CACtB,aAAa,QAAQ,EAAY,KAAK,UAAU,EAAc,MAAM,CAAC,EAGjE,MAAoB,CACxB,GAAI,CACF,IAAM,EAAQ,aAAa,QAAQ,EAAW,CAC1C,IAEF,EAAc,MADC,KAAK,MAAM,EAAM,CACH,IAAK,GAChC,OAAO,GAAS,SACZ,CAAE,MAAO,EAAM,SAAU,KAAM,UAAW,EAAG,CAC7C,EACL,QAEI,EAAO,CACd,QAAQ,MAAM,YAAa,EAAM,GAI/B,MAAqB,CACzB,EAAc,MAAQ,EAAE,CACxB,aAAa,WAAW,EAAW,EAG/B,EAAqB,GAAkB,CAC3C,EAAc,MAAM,OAAO,EAAO,EAAE,CACpC,aAAa,QAAQ,EAAY,KAAK,UAAU,EAAc,MAAM,CAAC,CACjE,EAAc,OAAS,EAAc,MAAM,SAC7C,EAAc,MAAQ,KAAK,IAAI,EAAG,EAAc,MAAM,OAAS,EAAE,GAK/D,EAAa,SAAY,CAC7B,EAAW,MAAQ,GACnB,EAAY,MAAQ,GACpB,EAAc,MAAQ,EACtB,MAAM,GAAU,CAChB,EAAe,OAAO,OAAO,EAGzB,MAAoB,CACxB,EAAW,MAAQ,GACnB,EAAY,MAAQ,GACpB,EAAc,MAAQ,GAIlB,EAAqB,GAA6B,CACtD,GAAI,EAAY,SAAU,CACxB,IAAM,EAAc,CAAC,CAAC,EAAY,SAAS,UAAU,OACrD,IAAW,EAAY,SAAS,IAAK,EAAY,CACjD,GAAa,MAEb,EAAY,MAAQ,EAAY,MAChC,EAAc,MAAQ,GAIpB,EAAc,GAAyB,CAC3C,EAAa,EAAK,CAClB,IAAM,EAAc,CAAC,CAAC,EAAK,UAAU,OACrC,IAAW,EAAK,IAAK,EAAY,CACjC,GAAa,EA+Cf,OAhBA,EAAM,MAAmB,CACvB,EAAc,MAAQ,GACtB,CAEF,MAAgB,CACd,GAAa,CACb,IAAM,EAAiB,GAAqB,EACrC,EAAE,SAAW,EAAE,UAAY,EAAE,MAAQ,MACxC,EAAE,gBAAgB,CAClB,GAAY,GAGhB,SAAS,iBAAiB,UAAW,EAAc,CACnD,MAAkB,SAAS,oBAAoB,UAAW,EAAc,CAAC,EACzE,CAEK,CACL,aACA,cACA,gBACA,iBACA,SACA,oBACA,iBACA,aACA,aACA,iBACA,iBACA,iBACA,eACA,oBACA,aACA,cACA,oBACA,aACA,gBA9DwB,CACxB,IAAM,EACJ,CAAC,EAAY,MAAM,MAAM,EAAI,EAAe,MAAM,OAAS,EACvD,EACJ,EAAY,MAAM,MAAM,EAAI,EAAkB,MAAM,OAAS,EAE/D,GAAI,EAAe,CACjB,IAAM,EAAc,EAAe,MAAM,EAAc,OACnD,GAAa,EAAkB,EAAY,SACtC,EAAc,CACvB,IAAM,EAAO,EAAkB,MAAM,EAAc,OAC/C,GAAM,EAAW,EAAK,GAoD5B,cAhDsB,CACtB,IAAM,EAAY,EAAY,MAAM,MAAM,CAEtC,EAAkB,MAAM,OAAS,EADjC,EAAe,MAAM,OAAS,EAElC,EAAc,MAAQ,KAAK,IAAI,EAAc,MAAQ,EAAG,EAAS,EA6CjE,cA1CsB,CACtB,EAAc,MAAQ,KAAK,IAAI,EAAc,MAAQ,EAAG,EAAE,EA0C3D,qpCCwCD,GAAM,CACJ,aACA,cACA,gBACA,iBACA,SACA,oBACA,iBACA,aACA,aACA,iBACA,kBACA,iBACA,eACA,qBACA,aACA,cACA,qBACA,cACA,cACA,YACA,aACE,EA5BU,EA4BY,QAAO,QAEjC,EAAa,CAAE,aAAY,cAAa,CAAA,aC7QxC,EA2NM,MA3NN,EA2NM,CA1NJ,EAAA,WAAe,CACf,EAQM,MAAA,CAPJ,MAAK,EAAA,CAAC,uBAAsB,CAAA,eACF,EAAA,EAAM,CAAA,CAAA,CAAA,CAC/B,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAU,WAElB,EAA+C,MAAA,CAA1C,MAAM,kCAAiC,CAAA,KAAA,GAAA,CAC5C,EAA0C,OAAA,CAApC,MAAM,qBAAoB,CAAC,KAAE,GAAA,CACnC,EAAkD,OAAA,CAA5C,MAAM,yBAAwB,CAAC,SAAM,GAAA,KAG7C,EAAA,UAAc,MACd,EA6MW,EAAA,CA7MD,GAAG,OAAM,CAAA,CACjB,EA2Ma,EAAA,CA3MD,KAAK,eAAc,CAAA,eA0MvB,CAxME,EAAA,EAAU,EAAA,GAAA,CADlB,EAyMM,MAAA,OAvMJ,MAAM,uBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAClB,UAAO,AAAA,EAAA,MAAA,GAAA,GAAA,IAAM,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,MAAA,CAAA,GAEzB,EAkMM,MAAA,CAjMJ,MAAK,EAAA,CAAC,yBAAwB,CAAA,cACL,EAAA,EAAM,CAAA,CAAA,CAAA,CAC9B,QAAK,AAAA,EAAA,KAAA,MAAN,GAAW,CAAA,OAAA,CAAA,GAEX,EAAA,SAAa,CACb,EAmBM,MAnBN,EAmBM,SAlBJ,EAA+C,MAAA,CAA1C,MAAM,kCAAiC,CAAA,KAAA,GAAA,GAC5C,EAUE,QAAA,SATI,iBAAJ,IAAI,uCACK,EAAW,MAAA,EAAA,KACpB,KAAK,OACJ,YAAaA,EAAAA,YACd,MAAM,qBACL,UAAO,kBAAM,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,MAAA,CAAA,kBACT,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,CAAA,CAAA,QAAA,CAAA,kBACN,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAS,CAAA,CAAA,aAAA,CAAA,kBACX,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAS,CAAA,CAAA,WAAA,CAAA,kBAPnB,EAAA,EAAW,CAAA,CAAA,CAAA,CAStB,EAKS,SAAA,CAJP,MAAM,kBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAW,WAEnB,EAA2B,MAAA,CAAtB,MAAM,cAAa,CAAA,KAAA,GAAA,CAAA,CAAA,GAI5B,EAAA,SAAa,CACb,EAyIM,MAzIN,EAyIM,CAxIJ,EAAA,QAAY,CAEH,EAAA,EAAU,CAIF,CAKH,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAc,CAAC,OAAM,GAAA,GAAA,CADzD,EA6DW,EAAA,CAAA,IAAA,EAAA,CAAA,CA9DX,EAAA,SAAa,CAIX,EAyDM,MAzDN,GAyDM,CAxDJ,EAuDM,MAvDN,EAuDM,CAtDJ,EAeM,MAfN,GAeM,SAdJ,EAEE,MAAA,CADA,MAAM,iDAAgD,CAAA,KAAA,GAAA,WACtD,SAEF,GAAA,CAAA,EAES,OAFT,GAES,EADP,EAAA,EAAc,CAAC,OAAM,CAAA,EAAA,CAEvB,EAMS,SAAA,CALP,MAAM,sBACL,QAAK,AAAA,EAAA,MAAA,GAAA,IAAE,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAAY,CACpB,MAAM,iBAEN,EAAoC,MAAA,CAA/B,MAAM,uBAAsB,CAAA,KAAA,GAAA,CAAA,CAAA,GAGrC,EAqCM,MArCN,GAqCM,EAAA,EAAA,GAAA,CApCJ,EAmCM,EAAA,KAAA,EAlC2B,EAAA,EAAc,EAArC,EAAa,SADvB,EAmCM,MAAA,CAjCH,IAAG,WAAa,IAChB,MAAK,EAAE,EAAA,EAAc,CAAC,EAAK,GAAA,CAAA,CAC3B,QAAK,GAAE,EAAA,GAAiB,CAAC,EAAW,CACpC,aAAU,GAAE,EAAA,MAAgB,IAGrB,EAAY,UAAU,MAAA,GAAA,CAD9B,EAIE,EAFK,EAAY,SAAS,KAAI,CAAA,OAC9B,MAAM,0BAER,EAKM,MALN,GAKM,AAAA,EAAA,MAAA,CADJ,EAA2C,MAAA,CAAtC,MAAM,8BAA6B,CAAA,KAAA,GAAA,CAAA,CAAA,EAE1C,EASM,MATN,GASM,CARJ,EAEM,MAFN,GAEM,EADD,EAAY,MAAK,CAAA,EAAA,CAEtB,EAIM,MAJN,GAIM,EAFF,EAAA,EAAc,CAAC,EAAY,UAAU,KAAG,GAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAI9C,EAMS,SAAA,CALP,MAAM,uBACL,QAAK,EAAA,GAAO,EAAA,GAAiB,CAAC,EAAK,CAAA,CAAA,OAAA,CAAA,CACpC,MAAM,kBAEN,EAA2B,MAAA,CAAtB,MAAM,cAAa,CAAA,KAAA,GAAA,CAAA,CAAA,EAAA,GAAA,6BASf,EAAA,EAAW,CAAC,MAAI,EAAA,GAAA,CAArC,EA6DW,EAAA,CAAA,IAAA,EAAA,CAAA,CA9DX,EAAA,SAAa,CAEX,EA2DM,MA3DN,GA2DM,CA1DJ,EAAA,UAAc,CAEL,EAAA,EAAU,EAIc,GAAA,CAIjC,EA+CM,EAAA,CAAA,IAAA,EAAA,CAAA,CAhDN,EAAA,WAAe,CACf,EA+CM,MA/CN,EA+CM,CA3CJ,EAMM,MANN,EAMM,SALJ,EAA2C,MAAA,CAAtC,MAAM,8BAA6B,CAAA,KAAA,GAAA,GAAG,IAC3C,EAAGE,EAAAA,iBAAgB,CAAG,IACtB,EAAA,CAAA,EAES,OAFT,EAES,EADP,EAAA,EAAiB,CAAC,OAAM,CAAA,EAAA,GAG5B,EAmCM,MAnCN,EAmCM,EAAA,EAAA,GAAA,CAlCJ,EAiCM,EAAA,KAAA,EAhCoB,EAAA,EAAiB,EAAjC,EAAM,SADhB,EAiCM,MAAA,CA/BH,IAAK,EAAK,IACV,MAAK,EAAE,EAAA,EAAc,CAAC,EAAK,GAAA,CAAA,CAC3B,QAAK,GAAE,EAAA,GAAU,CAAC,EAAI,CACtB,aAAU,GAAE,EAAA,MAAgB,IAGrB,EAAK,MAAA,GAAA,CADb,EAIE,EAFK,EAAK,KAAI,CAAA,OACd,MAAM,0BAER,EAKM,MALN,EAKM,AAAA,EAAA,MAAA,CADJ,EAA2C,MAAA,CAAtC,MAAM,8BAA6B,CAAA,KAAA,GAAA,CAAA,CAAA,EAE1C,EAQM,MARN,GAQM,CAPJ,EAGO,MAAA,CAFL,MAAM,mBACN,UAAQ,EAAA,GAAc,CAAC,EAAK,MAAO,EAAA,EAAW,CAAA,YAEhD,EAEM,MAFN,GAEM,EADD,EAAA,EAAc,CAAC,EAAK,IAAG,CAAA,CAAA,EAAA,CAAA,CAAA,CAItB,EAAK,UAAU,QAAA,GAAA,CADvB,EAKM,MALN,GAKM,EADD,EAAK,SAAS,OAAM,CAAA,EAAA,EAAA,EAAA,OAAA,GAAA,6BAnDZ,GAAA,CADnB,EAMM,MANN,EAMM,CAAA,AAAA,EAAA,MAFJ,EAA8C,MAAA,CAAzC,MAAM,iCAAgC,CAAA,KAAA,GAAA,CAC3C,EAAmC,IAAA,KAAhC,QAAK,EAAG,EAAA,EAAW,CAAA,CAAG,SAAM,EAAA,CAAA,CAAA,wBAhFlB,GAAA,CADnB,EAMM,MANN,GAMM,CAAA,AAAA,EAAA,MAFJ,EAA8C,MAAA,CAAzC,MAAM,iCAAgC,CAAA,KAAA,GAAA,CAC3C,EAAsB,IAAA,KAAA,EAAhBD,EAAAA,UAAS,CAAA,EAAA,CAAA,CAAA,IAoInB,EAAA,SAAa,CACb,EAyBM,MAzBN,GAyBM,CAAA,AAAA,EAAA,MAxBJ,EAUM,MAAA,CAVD,MAAM,uBAAsB,CAAA,CAC/B,EAEM,MAAA,CAFD,MAAM,oBAAmB,CAAA,CAC5B,EAAY,MAAA,KAAP,IAAC,CAAM,EAAe,OAAA,KAAT,KAAE,CAAA,CAAA,CAEtB,EAEM,MAAA,CAFD,MAAM,oBAAmB,CAAA,CAC5B,EAAa,MAAA,KAAR,KAAE,CAAM,EAAe,OAAA,KAAT,KAAE,CAAA,CAAA,CAEvB,EAEM,MAAA,CAFD,MAAM,oBAAmB,CAAA,CAC5B,EAAc,MAAA,KAAT,MAAG,CAAM,EAAe,OAAA,KAAT,KAAE,CAAA,CAAA,MAIlB,EAAA,EAAU,EAAA,GAAA,CADlB,EAYM,MAZN,GAYM,CARQ,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAU,EAAA,GAAA,CAA5C,EAEO,OAAA,GAFuC,MAC1C,EAAG,EAAA,EAAiB,CAAC,OAAM,CAAG,QAClC,EAAA,EAAA,CAEc,EAAA,EAAW,CAAC,MAAI,EAAM,EAAA,EAAc,CAAC,OAAM,GAAA,GAAA,CADzD,EAIO,OAAA,GAAA,EADF,EAAA,EAAc,CAAC,OAAM,CAAG,UAC7B,EAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA"}
|
package/dist/C_Guide.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Guide.js","names":[],"sources":["../src/components/C_Guide/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n"],"mappings":"stBAwCE,IAAM,EAAQ,EAeR,EAAO,EAYP,GAAA,EAAA,EAAA,cAEG,GADQ,EAAM,aAAa,WAAa,UAC9B,YAClB,CAGK,MAA6B,CACjC,GAAI,CAAC,EAAM,aAAa,QAAS,MAAO,GACxC,GAAI,CACF,OAAO,aAAa,QAAQ,EAAW,MAAM,GAAK,YAC5C,CACN,MAAO,KAKL,MAAsB,CACrB,KAAM,aAAa,QACxB,GAAI,CACF,aAAa,QAAQ,EAAW,MAAO,OAAM,MACvC,IAMJ,MAAuB,CAC3B,GAAI,CACF,aAAa,WAAW,EAAW,MAAK,MAClC,IASJ,MACG,EAAM,MAAM,OAAO,GAAQ,CAAC,EAAK,UAAU,CAAA,CAO9C,MAAkC,CACtC,IAAM,EAAU,CAAC,EAAM,aAAY,CACnC,GAAI,EAAM,MAAO,CAEf,IAAM,EAAO,SAAS,gBAClB,EAAM,MAAM,gBACd,EAAK,MAAM,YACT,uBACA,EAAM,MAAM,eACd,CACE,EAAM,MAAM,kBACd,EAAK,MAAM,YACT,yBACA,EAAM,MAAM,iBACd,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,oBACA,EAAM,MAAM,aACd,CACE,EAAM,MAAM,iBAAmB,IAAA,IACjC,EAAK,MAAM,YACT,4BACA,OAAO,EAAM,MAAM,eAAc,CACnC,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,mBACA,EAAM,MAAM,aACd,CAEJ,OAAO,EAAQ,OAAO,QAAQ,CAAC,KAAK,IAAG,EAOnC,GAAc,EAAQ,KAAU,CACpC,GAAI,CAAC,GAAS,GAAa,CAAE,OAE7B,IAAM,EAAc,GAAe,CACnC,GAAI,CAAC,EAAY,OAAQ,CACvB,QAAQ,KACN,+CACF,CACA,OAGF,IAAI,EAAmB,EAEjB,GAAA,EAAA,EAAA,QAAmB,CACvB,aAAc,GAAmB,CACjC,QAAS,EAAM,QACf,aAAc,EAAM,aACpB,WAAY,EAAM,WAClB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,MAAO,EAAY,IAAI,IAAS,CAC9B,QAAS,EAAK,QACd,QAAS,EAAK,QACf,EAAE,CACH,mBAAqB,GAAQ,CAC3B,IAAM,EAAO,EAAY,GACrB,IACF,EAAK,qBAAqB,EAA4B,EAAI,CAC1D,EAAK,cAAe,EAAkB,EAAI,GAG9C,aAAe,GAAQ,CACrB,IAAM,EAAO,EAAY,GACzB,GAAM,eAAe,EAA4B,EAAI,CACrD,KAEF,qBAAwB,CAClB,GAAoB,EAAY,QAClC,GAAc,CACd,EAAK,WAAU,EAEf,EAAK,QAAS,EAAgB,CAEhC,EAAU,SAAQ,EAErB,CAAA,CAED,EAAK,QAAO,CACZ,EAAU,OAAM,SAGlB,EAAa,CACX,aACA,iBACA,cACD,CAAA,QApMO,EAAM,cAAA,EAAA,EAAA,YAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAgBJ,EAAA,SAAA,CAAA,OAfR,UAAU,SACV,QAAQ,UAEG,SAAA,EAAA,EAAA,aASA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAAA,EAAA,QAAA,CAAA,CAPP,KAAA,GACC,QAAO,8BAKP,EAAA,EAAA,EAAA,aAAA,EAAA,EAAA,CAFE,KAAM,EAAM,YACZ,KAAM,yDAIyB,EAAA,EAAA,EAAA,oBAAA,OAAA,MAAA,EAAA,EAAA,iBAA7B,EAAM,eAAc,CAAA,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"C_Guide.js","names":[],"sources":["../src/components/C_Guide/index.vue","../src/components/C_Guide/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n"],"mappings":"stBAwCE,IAAM,EAAQ,EAeR,EAAO,EAYP,GAAA,EAAA,EAAA,cAEG,GADQ,EAAM,aAAa,WAAa,UAC9B,YAClB,CAGK,MAA6B,CACjC,GAAI,CAAC,EAAM,aAAa,QAAS,MAAO,GACxC,GAAI,CACF,OAAO,aAAa,QAAQ,EAAW,MAAM,GAAK,YAC5C,CACN,MAAO,KAKL,MAAsB,CACrB,KAAM,aAAa,QACxB,GAAI,CACF,aAAa,QAAQ,EAAW,MAAO,OAAM,MACvC,IAMJ,MAAuB,CAC3B,GAAI,CACF,aAAa,WAAW,EAAW,MAAK,MAClC,IASJ,MACG,EAAM,MAAM,OAAO,GAAQ,CAAC,EAAK,UAAU,CAAA,CAO9C,MAAkC,CACtC,IAAM,EAAU,CAAC,EAAM,aAAY,CACnC,GAAI,EAAM,MAAO,CAEf,IAAM,EAAO,SAAS,gBAClB,EAAM,MAAM,gBACd,EAAK,MAAM,YACT,uBACA,EAAM,MAAM,eACd,CACE,EAAM,MAAM,kBACd,EAAK,MAAM,YACT,yBACA,EAAM,MAAM,iBACd,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,oBACA,EAAM,MAAM,aACd,CACE,EAAM,MAAM,iBAAmB,IAAA,IACjC,EAAK,MAAM,YACT,4BACA,OAAO,EAAM,MAAM,eAAc,CACnC,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,mBACA,EAAM,MAAM,aACd,CAEJ,OAAO,EAAQ,OAAO,QAAQ,CAAC,KAAK,IAAG,EAOnC,GAAc,EAAQ,KAAU,CACpC,GAAI,CAAC,GAAS,GAAa,CAAE,OAE7B,IAAM,EAAc,GAAe,CACnC,GAAI,CAAC,EAAY,OAAQ,CACvB,QAAQ,KACN,+CACF,CACA,OAGF,IAAI,EAAmB,EAEjB,GAAA,EAAA,EAAA,QAAmB,CACvB,aAAc,GAAmB,CACjC,QAAS,EAAM,QACf,aAAc,EAAM,aACpB,WAAY,EAAM,WAClB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,MAAO,EAAY,IAAI,IAAS,CAC9B,QAAS,EAAK,QACd,QAAS,EAAK,QACf,EAAE,CACH,mBAAqB,GAAQ,CAC3B,IAAM,EAAO,EAAY,GACrB,IACF,EAAK,qBAAqB,EAA4B,EAAI,CAC1D,EAAK,cAAe,EAAkB,EAAI,GAG9C,aAAe,GAAQ,CACrB,IAAM,EAAO,EAAY,GACzB,GAAM,eAAe,EAA4B,EAAI,CACrD,KAEF,qBAAwB,CAClB,GAAoB,EAAY,QAClC,GAAc,CACd,EAAK,WAAU,EAEf,EAAK,QAAS,EAAgB,CAEhC,EAAU,SAAQ,EAErB,CAAA,CAED,EAAK,QAAO,CACZ,EAAU,OAAM,SAGlB,EAAa,CACX,aACA,iBACA,cACD,CAAA,QCpMO,EAAM,cAAA,EAAA,EAAA,YAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAgBH,EAAA,SAAA,CAAA,OAfT,UAAU,SACV,QAAQ,UAEG,SAAA,EAAA,EAAA,aASC,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAAA,EAAA,QAAA,CAAA,CAPR,KAAA,GACC,QAAO,8BAKN,EAAA,EAAA,EAAA,aAAA,EAAA,EAAA,CAFC,KAAM,EAAM,YACZ,KAAM,yDAI0B,EAAA,EAAA,EAAA,oBAAA,OAAA,MAAA,EAAA,EAAA,iBAA9B,EAAM,eAAc,CAAA,EAAA,CAAA,CAAA"}
|
package/dist/C_Guide2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./C_Icon2.js";import{
|
|
1
|
+
import{t as e}from"./C_Icon2.js";import{NButton as t,NTooltip as n}from"naive-ui";import{computed as r,createBlock as i,createCommentVNode as a,createElementVNode as o,createVNode as s,defineComponent as c,openBlock as l,toDisplayString as u,unref as d,withCtx as f}from"vue";import{driver as p}from"driver.js";import"driver.js/dist/driver.css";const m=c({name:`C_Guide`,__name:`index`,props:{steps:{default:()=>[]},doneBtnText:{default:`完成`},nextBtnText:{default:`下一步`},prevBtnText:{default:`上一步`},showProgress:{type:Boolean,default:!0},keyboard:{type:Boolean,default:!0},animate:{type:Boolean,default:!0},allowClose:{type:Boolean,default:!0},theme:{},persistence:{},popoverClass:{default:`driverjs-theme`},showTrigger:{type:Boolean,default:!0},triggerTooltip:{default:`功能引导`},triggerIcon:{default:`mdi:sign-routes`}},emits:[`start`,`complete`,`close`,`step-change`],setup(c,{expose:m,emit:h}){let g=c,_=h,v=r(()=>`${g.persistence?.keyPrefix??`c_guide`}_completed`),y=()=>{if(!g.persistence?.enabled)return!1;try{return localStorage.getItem(v.value)===`true`}catch{return!1}},b=()=>{if(g.persistence?.enabled)try{localStorage.setItem(v.value,`true`)}catch{}},x=()=>{try{localStorage.removeItem(v.value)}catch{}},S=()=>g.steps.filter(e=>!e.skipIf?.()),C=()=>{let e=[g.popoverClass];if(g.theme){let e=document.documentElement;g.theme.popoverBgColor&&e.style.setProperty(`--c-guide-popover-bg`,g.theme.popoverBgColor),g.theme.popoverTextColor&&e.style.setProperty(`--c-guide-popover-text`,g.theme.popoverTextColor),g.theme.primaryColor&&e.style.setProperty(`--c-guide-primary`,g.theme.primaryColor),g.theme.overlayOpacity!==void 0&&e.style.setProperty(`--c-guide-overlay-opacity`,String(g.theme.overlayOpacity)),g.theme.borderRadius&&e.style.setProperty(`--c-guide-radius`,g.theme.borderRadius)}return e.filter(Boolean).join(` `)},w=(e=!1)=>{if(!e&&y())return;let t=S();if(!t.length){console.warn(`[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。`);return}let n=0,r=p({popoverClass:C(),animate:g.animate,showProgress:g.showProgress,allowClose:g.allowClose,doneBtnText:g.doneBtnText,nextBtnText:g.nextBtnText,prevBtnText:g.prevBtnText,steps:t.map(e=>({element:e.element,popover:e.popover})),onHighlightStarted:e=>{let r=t[n];r&&(r.onHighlightStarted?.(e,r),_(`step-change`,n,r))},onDeselected:e=>{let r=t[n];r?.onDeselected?.(e,r),n++},onDestroyStarted:()=>{n>=t.length?(b(),_(`complete`)):_(`close`,n),r.destroy()}});_(`start`),r.drive()};return m({startGuide:w,resetCompleted:x,isCompleted:y}),(r,c)=>g.showTrigger?(l(),i(d(n),{key:0,placement:`bottom`,trigger:`hover`},{trigger:f(()=>[s(d(t),{text:``,onClick:w},{default:f(()=>[s(e,{name:g.triggerIcon,size:18},null,8,[`name`])]),_:1})]),default:f(()=>[o(`span`,null,u(g.triggerTooltip),1)]),_:1})):a(`v-if`,!0)}});export{m as t};
|
|
2
2
|
//# sourceMappingURL=C_Guide2.js.map
|
package/dist/C_Guide2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Guide2.js","names":[],"sources":["../src/components/C_Guide/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n"],"mappings":"+3BAwCE,IAAM,EAAQ,EAeR,EAAO,EAYP,EAAa,MAEV,GADQ,EAAM,aAAa,WAAa,UAC9B,YAClB,CAGK,MAA6B,CACjC,GAAI,CAAC,EAAM,aAAa,QAAS,MAAO,GACxC,GAAI,CACF,OAAO,aAAa,QAAQ,EAAW,MAAM,GAAK,YAC5C,CACN,MAAO,KAKL,MAAsB,CACrB,KAAM,aAAa,QACxB,GAAI,CACF,aAAa,QAAQ,EAAW,MAAO,OAAM,MACvC,IAMJ,MAAuB,CAC3B,GAAI,CACF,aAAa,WAAW,EAAW,MAAK,MAClC,IASJ,MACG,EAAM,MAAM,OAAO,GAAQ,CAAC,EAAK,UAAU,CAAA,CAO9C,MAAkC,CACtC,IAAM,EAAU,CAAC,EAAM,aAAY,CACnC,GAAI,EAAM,MAAO,CAEf,IAAM,EAAO,SAAS,gBAClB,EAAM,MAAM,gBACd,EAAK,MAAM,YACT,uBACA,EAAM,MAAM,eACd,CACE,EAAM,MAAM,kBACd,EAAK,MAAM,YACT,yBACA,EAAM,MAAM,iBACd,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,oBACA,EAAM,MAAM,aACd,CACE,EAAM,MAAM,iBAAmB,IAAA,IACjC,EAAK,MAAM,YACT,4BACA,OAAO,EAAM,MAAM,eAAc,CACnC,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,mBACA,EAAM,MAAM,aACd,CAEJ,OAAO,EAAQ,OAAO,QAAQ,CAAC,KAAK,IAAG,EAOnC,GAAc,EAAQ,KAAU,CACpC,GAAI,CAAC,GAAS,GAAa,CAAE,OAE7B,IAAM,EAAc,GAAe,CACnC,GAAI,CAAC,EAAY,OAAQ,CACvB,QAAQ,KACN,+CACF,CACA,OAGF,IAAI,EAAmB,EAEjB,EAAY,EAAO,CACvB,aAAc,GAAmB,CACjC,QAAS,EAAM,QACf,aAAc,EAAM,aACpB,WAAY,EAAM,WAClB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,MAAO,EAAY,IAAI,IAAS,CAC9B,QAAS,EAAK,QACd,QAAS,EAAK,QACf,EAAE,CACH,mBAAqB,GAAQ,CAC3B,IAAM,EAAO,EAAY,GACrB,IACF,EAAK,qBAAqB,EAA4B,EAAI,CAC1D,EAAK,cAAe,EAAkB,EAAI,GAG9C,aAAe,GAAQ,CACrB,IAAM,EAAO,EAAY,GACzB,GAAM,eAAe,EAA4B,EAAI,CACrD,KAEF,qBAAwB,CAClB,GAAoB,EAAY,QAClC,GAAc,CACd,EAAK,WAAU,EAEf,EAAK,QAAS,EAAgB,CAEhC,EAAU,SAAQ,EAErB,CAAA,CAED,EAAK,QAAO,CACZ,EAAU,OAAM,SAGlB,EAAa,CACX,aACA,iBACA,cACD,CAAA,QApMO,EAAM,aAAA,GAAA,CADd,EAiBU,EAAA,EAAA,CAAA,OAfR,UAAU,SACV,QAAQ,UAEG,QAAO,MASP,CART,EAQS,EAAA,EAAA,CAAA,CAPP,KAAA,GACC,QAAO,kBAKP,CAHD,EAGC,EAAA,CAFE,KAAM,EAAM,YACZ,KAAM,6CAIyB,CAAtC,EAAsC,OAAA,KAAA,EAA7B,EAAM,eAAc,CAAA,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"C_Guide2.js","names":[],"sources":["../src/components/C_Guide/index.vue","../src/components/C_Guide/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-06\n * @Description: 用户引导组件(基于 driver.js)— 增强版\n * 支持:步骤分组 / 键盘导航 / 步骤回调 / 主题自定义 / 完成持久化\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <NTooltip\n v-if=\"props.showTrigger\"\n placement=\"bottom\"\n trigger=\"hover\"\n >\n <template #trigger>\n <NButton\n text\n @click=\"startGuide\"\n >\n <C_Icon\n :name=\"props.triggerIcon\"\n :size=\"18\"\n />\n </NButton>\n </template>\n <span>{{ props.triggerTooltip }}</span>\n </NTooltip>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { NTooltip, NButton } from 'naive-ui'\n import C_Icon from '../C_Icon/index.vue'\n import { driver } from 'driver.js'\n import 'driver.js/dist/driver.css'\n import type { GuideProps, GuideStep } from './types'\n\n defineOptions({ name: 'C_Guide' })\n\n const props = withDefaults(defineProps<GuideProps>(), {\n steps: () => [],\n doneBtnText: '完成',\n nextBtnText: '下一步',\n prevBtnText: '上一步',\n showProgress: true,\n keyboard: true,\n animate: true,\n allowClose: true,\n popoverClass: 'driverjs-theme',\n showTrigger: true,\n triggerTooltip: '功能引导',\n triggerIcon: 'mdi:sign-routes',\n })\n\n const emit = defineEmits<{\n /** 引导开始 */\n start: []\n /** 引导完成(走完全部步骤) */\n complete: []\n /** 引导被用户关闭(未完成) */\n close: [currentStep: number]\n /** 步骤切换 */\n 'step-change': [stepIndex: number, step: GuideStep]\n }>()\n\n /** 持久化 key */\n const persistKey = computed(() => {\n const prefix = props.persistence?.keyPrefix ?? 'c_guide'\n return `${prefix}_completed`\n })\n\n /** 是否已完成引导 */\n const isCompleted = (): boolean => {\n if (!props.persistence?.enabled) return false\n try {\n return localStorage.getItem(persistKey.value) === 'true'\n } catch {\n return false\n }\n }\n\n /** 标记引导已完成 */\n const markCompleted = () => {\n if (!props.persistence?.enabled) return\n try {\n localStorage.setItem(persistKey.value, 'true')\n } catch {\n // localStorage 不可用时静默忽略\n }\n }\n\n /** 重置完成状态 */\n const resetCompleted = () => {\n try {\n localStorage.removeItem(persistKey.value)\n } catch {\n // 静默忽略\n }\n }\n\n /**\n * * @description: 过滤掉需要跳过的步骤\n * ! @return 有效步骤列表\n */\n const getActiveSteps = (): GuideStep[] => {\n return props.steps.filter(step => !step.skipIf?.())\n }\n\n /**\n * * @description: 构建主题相关的 CSS 变量\n * ! @return popoverClass 字符串\n */\n const buildPopoverClass = (): string => {\n const classes = [props.popoverClass]\n if (props.theme) {\n // 通过 CSS 变量注入主题\n const root = document.documentElement\n if (props.theme.popoverBgColor)\n root.style.setProperty(\n '--c-guide-popover-bg',\n props.theme.popoverBgColor\n )\n if (props.theme.popoverTextColor)\n root.style.setProperty(\n '--c-guide-popover-text',\n props.theme.popoverTextColor\n )\n if (props.theme.primaryColor)\n root.style.setProperty(\n '--c-guide-primary',\n props.theme.primaryColor\n )\n if (props.theme.overlayOpacity !== undefined)\n root.style.setProperty(\n '--c-guide-overlay-opacity',\n String(props.theme.overlayOpacity)\n )\n if (props.theme.borderRadius)\n root.style.setProperty(\n '--c-guide-radius',\n props.theme.borderRadius\n )\n }\n return classes.filter(Boolean).join(' ')\n }\n\n /**\n * * @description: 启动引导流程\n * ? @param {boolean} force 是否强制启动(忽略持久化状态)\n */\n const startGuide = (force = false) => {\n if (!force && isCompleted()) return\n\n const activeSteps = getActiveSteps()\n if (!activeSteps.length) {\n console.warn(\n '[C_Guide] 未提供引导步骤(steps),请通过 :steps prop 传入。'\n )\n return\n }\n\n let currentStepIndex = 0\n\n const driverObj = driver({\n popoverClass: buildPopoverClass(),\n animate: props.animate,\n showProgress: props.showProgress,\n allowClose: props.allowClose,\n doneBtnText: props.doneBtnText,\n nextBtnText: props.nextBtnText,\n prevBtnText: props.prevBtnText,\n steps: activeSteps.map(step => ({\n element: step.element,\n popover: step.popover,\n })),\n onHighlightStarted: (_el) => {\n const step = activeSteps[currentStepIndex]\n if (step) {\n step.onHighlightStarted?.(_el as Element | undefined, step)\n emit('step-change', currentStepIndex, step)\n }\n },\n onDeselected: (_el) => {\n const step = activeSteps[currentStepIndex]\n step?.onDeselected?.(_el as Element | undefined, step)\n currentStepIndex++\n },\n onDestroyStarted: () => {\n if (currentStepIndex >= activeSteps.length) {\n markCompleted()\n emit('complete')\n } else {\n emit('close', currentStepIndex)\n }\n driverObj.destroy()\n },\n })\n\n emit('start')\n driverObj.drive()\n }\n\n defineExpose({\n startGuide,\n resetCompleted,\n isCompleted,\n })\n</script>\n"],"mappings":"+3BAwCE,IAAM,EAAQ,EAeR,EAAO,EAYP,EAAa,MAEV,GADQ,EAAM,aAAa,WAAa,UAC9B,YAClB,CAGK,MAA6B,CACjC,GAAI,CAAC,EAAM,aAAa,QAAS,MAAO,GACxC,GAAI,CACF,OAAO,aAAa,QAAQ,EAAW,MAAM,GAAK,YAC5C,CACN,MAAO,KAKL,MAAsB,CACrB,KAAM,aAAa,QACxB,GAAI,CACF,aAAa,QAAQ,EAAW,MAAO,OAAM,MACvC,IAMJ,MAAuB,CAC3B,GAAI,CACF,aAAa,WAAW,EAAW,MAAK,MAClC,IASJ,MACG,EAAM,MAAM,OAAO,GAAQ,CAAC,EAAK,UAAU,CAAA,CAO9C,MAAkC,CACtC,IAAM,EAAU,CAAC,EAAM,aAAY,CACnC,GAAI,EAAM,MAAO,CAEf,IAAM,EAAO,SAAS,gBAClB,EAAM,MAAM,gBACd,EAAK,MAAM,YACT,uBACA,EAAM,MAAM,eACd,CACE,EAAM,MAAM,kBACd,EAAK,MAAM,YACT,yBACA,EAAM,MAAM,iBACd,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,oBACA,EAAM,MAAM,aACd,CACE,EAAM,MAAM,iBAAmB,IAAA,IACjC,EAAK,MAAM,YACT,4BACA,OAAO,EAAM,MAAM,eAAc,CACnC,CACE,EAAM,MAAM,cACd,EAAK,MAAM,YACT,mBACA,EAAM,MAAM,aACd,CAEJ,OAAO,EAAQ,OAAO,QAAQ,CAAC,KAAK,IAAG,EAOnC,GAAc,EAAQ,KAAU,CACpC,GAAI,CAAC,GAAS,GAAa,CAAE,OAE7B,IAAM,EAAc,GAAe,CACnC,GAAI,CAAC,EAAY,OAAQ,CACvB,QAAQ,KACN,+CACF,CACA,OAGF,IAAI,EAAmB,EAEjB,EAAY,EAAO,CACvB,aAAc,GAAmB,CACjC,QAAS,EAAM,QACf,aAAc,EAAM,aACpB,WAAY,EAAM,WAClB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,MAAO,EAAY,IAAI,IAAS,CAC9B,QAAS,EAAK,QACd,QAAS,EAAK,QACf,EAAE,CACH,mBAAqB,GAAQ,CAC3B,IAAM,EAAO,EAAY,GACrB,IACF,EAAK,qBAAqB,EAA4B,EAAI,CAC1D,EAAK,cAAe,EAAkB,EAAI,GAG9C,aAAe,GAAQ,CACrB,IAAM,EAAO,EAAY,GACzB,GAAM,eAAe,EAA4B,EAAI,CACrD,KAEF,qBAAwB,CAClB,GAAoB,EAAY,QAClC,GAAc,CACd,EAAK,WAAU,EAEf,EAAK,QAAS,EAAgB,CAEhC,EAAU,SAAQ,EAErB,CAAA,CAED,EAAK,QAAO,CACZ,EAAU,OAAM,SAGlB,EAAa,CACX,aACA,iBACA,cACD,CAAA,QCpMO,EAAM,aAAA,GAAA,CADd,EAiBW,EAAA,EAAA,CAAA,OAfT,UAAU,SACV,QAAQ,UAEG,QAAO,MASN,CARV,EAQU,EAAA,EAAA,CAAA,CAPR,KAAA,GACC,QAAO,kBAKN,CAHF,EAGE,EAAA,CAFC,KAAM,EAAM,YACZ,KAAM,6CAI0B,CAAvC,EAAuC,OAAA,KAAA,EAA9B,EAAM,eAAc,CAAA,EAAA,CAAA,CAAA"}
|
package/dist/C_Icon.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as IconProps, t as _default } from "./index15.vue.js";
|
|
2
2
|
export { _default as C_Icon, type IconProps };
|
package/dist/C_Icon.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as IconProps, t as _default } from "./index15.vue.js";
|
|
2
2
|
export { _default as C_Icon, type IconProps };
|