@robot-admin/naive-ui-components 0.6.2 → 0.6.4
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 +48 -48
- package/README.md +18 -14
- package/dist/C_ActionBar-DYG0Yf3A.css.map +1 -0
- package/dist/C_ActionBar-MAjRhqcI.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-A3NXx_sF.css.map → C_AntV-BY8jqqmi.css.map} +1 -1
- package/dist/{C_AntV-D2Zp2qQF.css.map → C_AntV-BbkHc-_a.css.map} +1 -1
- package/dist/C_AntV.css +78 -78
- package/dist/C_AntV.js.map +1 -1
- package/dist/C_AntV2.js +2 -2
- package/dist/C_AntV2.js.map +1 -1
- package/dist/{C_Barcode-DjTmDkbQ.css.map → C_Barcode-DYDRDe2O.css.map} +1 -1
- package/dist/{C_Barcode-Do1Ozsmh.css.map → C_Barcode-muJdc_O4.css.map} +1 -1
- package/dist/C_Barcode.css +7 -7
- package/dist/C_Barcode.js.map +1 -1
- package/dist/C_Barcode2.js +1 -1
- package/dist/C_Barcode2.js.map +1 -1
- package/dist/C_Breadcrumb-D55Jd2CK.css.map +1 -0
- package/dist/C_Breadcrumb-mBL4CWps.css.map +1 -0
- package/dist/C_Breadcrumb.css +7 -0
- package/dist/C_Breadcrumb.js.map +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/{C_Captcha-CZmAETly.css.map → C_Captcha-9_hk6VmY.css.map} +1 -1
- package/dist/{C_Captcha-Ccq3DMrR.css.map → C_Captcha-MtASlJ0f.css.map} +1 -1
- package/dist/C_Captcha.css +19 -19
- package/dist/C_Captcha.js.map +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Captcha2.js.map +1 -1
- package/dist/{C_City-Cv5BESaN.css.map → C_City-Bam08Qv3.css.map} +1 -1
- package/dist/{C_City-DNKv4MpH.css.map → C_City-Bb3W-KaN.css.map} +1 -1
- package/dist/C_City.css +29 -29
- package/dist/C_City.js.map +1 -1
- package/dist/C_City2.js +1 -1
- package/dist/C_City2.js.map +1 -1
- package/dist/C_Code-BFi5xxnM.css.map +1 -0
- package/dist/C_Code-CZ7yfnri.css.map +1 -0
- package/dist/C_Code.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-BpofCDyl.css.map → C_CollapsePanel-BCmTFuDz.css.map} +1 -1
- package/dist/{C_CollapsePanel-Fap-lv_5.css.map → C_CollapsePanel-Bxnh4Zy-.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_Cron-C0-8b5af.css.map → C_Cron-Civir5-I.css.map} +1 -1
- package/dist/{C_Cron-DqHQ92LN.css.map → C_Cron-iw3qpMsy.css.map} +1 -1
- package/dist/C_Cron.css +37 -37
- 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_Draggable-Bq6o0qXn.css.map → C_Draggable-BCjIvIwT.css.map} +1 -1
- package/dist/{C_Draggable-r6nhx3yM.css.map → C_Draggable-DwkSlCOS.css.map} +1 -1
- package/dist/C_Draggable.css +46 -46
- package/dist/C_Draggable.js.map +1 -1
- package/dist/C_Draggable2.js +1 -1
- package/dist/C_Draggable2.js.map +1 -1
- package/dist/{C_FilePreview-BVarVvnD.css.map → C_FilePreview-BhcbiXsV.css.map} +1 -1
- package/dist/{C_FilePreview-DHGlV4OR.css.map → C_FilePreview-DJudcIbW.css.map} +1 -1
- package/dist/C_FilePreview.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-BciQUPpS.css.map → C_Form-BtcAPIRi.css.map} +1 -1
- package/dist/{C_Form-CKHvXL3O.css.map → C_Form-D_gwQ7hC.css.map} +1 -1
- package/dist/C_Form.css +222 -222
- package/dist/C_Form.js.map +1 -1
- package/dist/C_Form2.js +1 -1
- package/dist/C_Form2.js.map +1 -1
- package/dist/{C_FormSearch-Bmd2CmG6.css.map → C_FormSearch-Bi4XYjjk.css.map} +1 -1
- package/dist/{C_FormSearch-DBNtnjaL.css.map → C_FormSearch-DUGOoX0u.css.map} +1 -1
- package/dist/C_FormSearch.css +45 -45
- package/dist/C_FormSearch.js.map +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormSearch2.js.map +1 -1
- package/dist/{C_FormulaEditor-3WG2vtQl.css.map → C_FormulaEditor-CJk3SSUJ.css.map} +1 -1
- package/dist/{C_FormulaEditor-Cm0CokN5.css.map → C_FormulaEditor-Cy7mjfVO.css.map} +1 -1
- package/dist/C_FormulaEditor.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-BQA0OjGB.css.map +1 -0
- package/dist/C_FullCalendar-ChJUosAi.css.map +1 -0
- package/dist/C_FullCalendar.css +3 -3
- package/dist/C_FullCalendar.js.map +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_FullCalendar2.js.map +1 -1
- package/dist/C_Icon.js.map +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/{C_ImageCropper-D3L2-J_J.css.map → C_ImageCropper-BqZpkZfU.css.map} +1 -1
- package/dist/{C_ImageCropper-DrmUlaLi.css.map → C_ImageCropper-CylwGuzS.css.map} +1 -1
- package/dist/C_ImageCropper.css +10 -10
- 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_Map-BCJmDnJT.css.map → C_Map-DNnBcY70.css.map} +1 -1
- package/dist/{C_Map-WUMXSAfy.css.map → C_Map-LEXIx6zM.css.map} +1 -1
- package/dist/C_Map.css +4 -4
- package/dist/C_Map.js.map +1 -1
- package/dist/C_Map2.js +1 -1
- package/dist/C_Map2.js.map +1 -1
- package/dist/{C_Markdown-7iBnLDtL.css.map → C_Markdown-Kujzx1qG.css.map} +1 -1
- package/dist/{C_Markdown-BbTvdFCl.css.map → C_Markdown-YCAmBbNF.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.map +1 -1
- package/dist/{C_QRCode-DMxSyogU.css.map → C_QRCode-CFNTda_1.css.map} +1 -1
- package/dist/{C_QRCode-G7fiAkm4.css.map → C_QRCode-CmWr9lK-.css.map} +1 -1
- package/dist/C_QRCode.css +9 -9
- package/dist/C_QRCode.js.map +1 -1
- package/dist/C_QRCode2.js +1 -1
- package/dist/C_QRCode2.js.map +1 -1
- package/dist/{C_Signature-B5fFz6RD.css.map → C_Signature-PN4GOLRX.css.map} +1 -1
- package/dist/{C_Signature-es-ZNPzr.css.map → C_Signature-fWQqGIZ-.css.map} +1 -1
- package/dist/C_Signature.css +14 -14
- 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_SplitPane-Br2eK8IG.css.map → C_SplitPane-BOwr1C7K.css.map} +1 -1
- package/dist/{C_SplitPane-DuyzUhKB.css.map → C_SplitPane-N-a_D-7F.css.map} +1 -1
- package/dist/C_SplitPane.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-DGwXxS2Y.css.map → C_Steps-DLW2vbqC.css.map} +1 -1
- package/dist/{C_Steps-P9Qj9iDd.css.map → C_Steps-DwMRHbG2.css.map} +1 -1
- package/dist/C_Steps.css +37 -37
- 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-vZlcgH6x.css.map → C_Table-BV1wUw6f.css.map} +1 -1
- package/dist/{C_Table-wzAO43l0.css.map → C_Table-LlJ-JEdm.css.map} +1 -1
- package/dist/C_Table.css +93 -93
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +1 -1
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-BsutyC3U.css.map → C_TagsView-DX3LecK1.css.map} +1 -1
- package/dist/{C_TagsView-Crm7yWg9.css.map → C_TagsView-DqOTa8bL.css.map} +1 -1
- package/dist/C_TagsView.css +36 -36
- 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_Time-BzyQVvTS.css.map +1 -0
- package/dist/C_Time-DmpKLQHc.css.map +1 -0
- package/dist/C_Time.css +5 -5
- package/dist/C_Time.js.map +1 -1
- package/dist/C_Time2.js +1 -1
- package/dist/C_Time2.js.map +1 -1
- package/dist/{C_Tree-B-Le4hjQ.css.map → C_Tree-D98nX9qT.css.map} +1 -1
- package/dist/{C_Tree-DnGc_MPb.css.map → C_Tree-ulfm7b-P.css.map} +1 -1
- package/dist/C_Tree.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_VideoPlayer-Cdgv4Zq0.css.map → C_VideoPlayer-4J96tKfK.css.map} +1 -1
- package/dist/{C_VideoPlayer-rm0MODUv.css.map → C_VideoPlayer-D35seHkm.css.map} +1 -1
- package/dist/C_VideoPlayer.css +13 -13
- package/dist/C_VideoPlayer.js.map +1 -1
- package/dist/C_VideoPlayer2.js +1 -1
- package/dist/C_VideoPlayer2.js.map +1 -1
- package/dist/{C_VtableGantt-BpY-Rng3.css.map → C_VtableGantt-C2lxFmWg.css.map} +1 -1
- package/dist/{C_VtableGantt-DB87-jdS.css.map → C_VtableGantt-Dwnkw_WL.css.map} +1 -1
- package/dist/C_VtableGantt.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_WorkFlow-7F6op6qN.css.map → C_WorkFlow-2hJfvvTK.css.map} +1 -1
- package/dist/{C_WorkFlow-Cy3HWA6A.css.map → C_WorkFlow-DHoNjl8-.css.map} +1 -1
- package/dist/C_WorkFlow.css +108 -108
- 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 +4 -4
- package/dist/constants2.d.ts +5 -5
- package/dist/constants3.d.ts +1 -1
- package/dist/constants4.d.ts +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index11.vue.d.ts +3 -3
- package/dist/index12.vue.d.ts +2 -2
- package/dist/index13.vue.d.ts +5 -5
- package/dist/index15.vue.d.ts +1 -1
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index19.vue.d.ts +1 -1
- package/dist/index4.vue.d.ts +6 -6
- package/dist/index5.vue.d.ts +2 -2
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index7.vue.d.ts +1 -1
- package/dist/index8.vue.d.ts +1 -1
- package/dist/index9.vue.d.ts +2 -2
- package/dist/menuAdapter.js.map +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +1218 -1209
- package/dist/useCollapsePanel.d.ts +1 -1
- package/dist/useDraggableLayout.d.ts +2 -2
- package/dist/useDynamicFormState.d.ts +118 -118
- package/dist/useInfiniteScroll.d.ts +2 -2
- package/dist/useQRCode.d.ts +1 -1
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSplitResize.d.ts +2 -2
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +4 -4
- package/dist/useWorkflowValidation.d.ts +2 -2
- package/package.json +1 -1
- package/dist/C_ActionBar-jZPsiXtT.css.map +0 -1
- package/dist/C_ActionBar-nnfbZCea.css.map +0 -1
- package/dist/C_Code-DPZlNSxL.css.map +0 -1
- package/dist/C_Code-avZjAnHD.css.map +0 -1
- package/dist/C_FullCalendar-1U4VlG7X.css.map +0 -1
- package/dist/C_FullCalendar-DLUdCtqf.css.map +0 -1
- package/dist/C_Time-Bd_e1YDN.css.map +0 -1
- package/dist/C_Time-CKb_fwdm.css.map +0 -1
package/dist/C_Map2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Map2.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-12-02\r\n * @Description: 地图组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-map\">\r\n <div\r\n ref=\"mapContainer\"\r\n class=\"map-container\"\r\n :style=\"{ height: height }\"\r\n ></div>\r\n <div v-if=\"loading\" class=\"map-loading\">\r\n <NSpin size=\"large\" />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\r\nimport { NSpin } from \"naive-ui\";\r\nimport L from \"leaflet\";\r\nimport \"leaflet/dist/leaflet.css\";\r\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\r\n\r\ndefineOptions({ name: \"C_Map\" });\r\n\r\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\r\nL.Icon.Default.mergeOptions(MAP_ICONS);\r\n\r\ninterface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: \"osm\" | \"amap\";\r\n amapKey?: string;\r\n }>(),\r\n {\r\n height: \"400px\",\r\n center: () => [39.9042, 116.4074],\r\n zoom: 10,\r\n markers: () => [],\r\n mapType: \"osm\",\r\n amapKey: \"\",\r\n },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n ready: [map: any];\r\n markerClick: [marker: MapMarker, event: any];\r\n}>();\r\n\r\nconst mapContainer = ref<HTMLElement>();\r\nconst loading = ref(true);\r\nlet map: any = null;\r\n\r\nconst initOSMMap = async () => {\r\n if (!mapContainer.value) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n map = L.map(mapContainer.value, {\r\n center: props.center,\r\n zoom: props.zoom,\r\n zoomControl: true,\r\n preferCanvas: true,\r\n });\r\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\r\n tileLayer.addTo(map);\r\n addMarkers();\r\n await nextTick();\r\n requestAnimationFrame(() => {\r\n map?.invalidateSize({ reset: true, pan: false });\r\n });\r\n loading.value = false;\r\n emit(\"ready\", map);\r\n } catch (error) {\r\n console.error(\"OpenStreetMap初始化失败:\", error);\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst initAMap = async () => {\r\n if (!mapContainer.value || !props.amapKey) return;\r\n try {\r\n mapContainer.value.innerHTML = \"\";\r\n const script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\r\n script.onload = () => {\r\n if ((window as any).AMap) {\r\n const amap = new (window as any).AMap.Map(mapContainer.value, {\r\n zoom: props.zoom,\r\n center: props.center,\r\n });\r\n addAMapMarkers(amap);\r\n loading.value = false;\r\n emit(\"ready\", amap);\r\n }\r\n };\r\n script.onerror = () => {\r\n loading.value = false;\r\n };\r\n document.head.appendChild(script);\r\n } catch {\r\n loading.value = false;\r\n }\r\n};\r\n\r\nconst addMarkers = () => {\r\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\r\n map.eachLayer((layer: any) => {\r\n if (layer instanceof L.Marker) {\r\n map.removeLayer(layer);\r\n }\r\n });\r\n props.markers.forEach((marker) => {\r\n const leafletMarker = L.marker([marker.lat, marker.lng]);\r\n if (marker.popup) {\r\n leafletMarker.bindPopup(marker.popup);\r\n leafletMarker.on(\"click\", (event: any) => {\r\n emit(\"markerClick\", marker, event);\r\n });\r\n }\r\n leafletMarker.addTo(map);\r\n });\r\n};\r\n\r\nconst addAMapMarkers = (amap: any) => {\r\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\r\n props.markers.forEach((marker) => {\r\n const amapMarker = new (window as any).AMap.Marker({\r\n position: [marker.lat, marker.lng],\r\n title: marker.popup || \"\",\r\n });\r\n if (marker.popup) {\r\n const infoWindow = new (window as any).AMap.InfoWindow({\r\n content: marker.popup,\r\n offset: new (window as any).AMap.Pixel(0, -30),\r\n });\r\n amapMarker.on(\"click\", () => {\r\n infoWindow.open(amap, amapMarker.getPosition());\r\n emit(\"markerClick\", marker, null);\r\n });\r\n }\r\n amapMarker.setMap(amap);\r\n });\r\n};\r\n\r\nwatch(\r\n () => props.markers,\r\n () => {\r\n if (map && props.mapType === \"osm\") addMarkers();\r\n },\r\n { deep: true },\r\n);\r\n\r\nwatch(\r\n () => props.mapType,\r\n async (newType, oldType) => {\r\n if (newType === oldType) return;\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n loading.value = true;\r\n await nextTick();\r\n if (newType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n }\r\n },\r\n);\r\n\r\nwatch(\r\n [() => props.center, () => props.zoom],\r\n () => {\r\n if (map) map.setView(props.center, props.zoom);\r\n },\r\n { deep: true },\r\n);\r\n\r\nonMounted(async () => {\r\n await nextTick();\r\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\r\n else await initOSMMap();\r\n});\r\n\r\nonUnmounted(() => {\r\n if (map) {\r\n map.remove();\r\n map = null;\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"+WAAA,MAAa,EAAY,CACvB,CAAE,MAAO,gBAAiB,MAAO,MAAO,CACxC,CAAE,MAAO,OAAQ,MAAO,OAAQ,CACjC,CAmBY,EAET,CACF,OAAQ,QACR,OAAQ,CAAC,QAAS,SAAS,CAC3B,KAAM,GACN,QAAS,MACV,CAEY,EAAkB,CAC7B,IAAK,qDACL,YAAa,+BACb,QAAS,GACT,QAAS,EACT,SAAU,IACV,aAAc,GACf,CAEY,EAAc,CACzB,OAAQ,0CACR,KAAM,8EACP,CAEY,EAAY,CACvB,cACE,iFACF,QACE,8EACF,UACE,gFACH,ySGvBD,OAAQ,EAAE,KAAK,QAAQ,UAAkB,YACzC,EAAE,KAAK,QAAQ,aAAa,EAAU,CAQtC,IAAM,EAAQ,EAmBR,EAAO,EAKP,EAAe,GAAkB,CACjC,EAAU,EAAI,GAAK,CACrB,EAAW,KAET,EAAa,SAAY,CACxB,KAAa,MAClB,GAAI,CACF,EAAa,MAAM,UAAY,GAC/B,EAAM,EAAE,IAAI,EAAa,MAAO,CAC9B,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,YAAa,GACb,aAAc,GACf,CAAC,CACgB,EAAE,UAAU,EAAgB,IAAK,EAAgB,CACzD,MAAM,EAAI,CACpB,GAAY,CACZ,MAAM,GAAU,CAChB,0BAA4B,CAC1B,GAAK,eAAe,CAAE,MAAO,GAAM,IAAK,GAAO,CAAC,EAChD,CACF,EAAQ,MAAQ,GAChB,EAAK,QAAS,EAAI,OACX,EAAO,CACd,QAAQ,MAAM,sBAAuB,EAAM,CAC3C,EAAQ,MAAQ,KAId,EAAW,SAAY,CACvB,MAAC,EAAa,OAAS,CAAC,EAAM,SAClC,GAAI,CACF,EAAa,MAAM,UAAY,GAC/B,IAAM,EAAS,SAAS,cAAc,SAAS,CAC/C,EAAO,KAAO,kBACd,EAAO,IAAM,GAAG,EAAY,SAAS,EAAM,UAC3C,EAAO,WAAe,CACpB,GAAK,OAAe,KAAM,CACxB,IAAM,EAAO,IAAK,OAAe,KAAK,IAAI,EAAa,MAAO,CAC5D,KAAM,EAAM,KACZ,OAAQ,EAAM,OACf,CAAC,CACF,EAAe,EAAK,CACpB,EAAQ,MAAQ,GAChB,EAAK,QAAS,EAAK,GAGvB,EAAO,YAAgB,CACrB,EAAQ,MAAQ,IAElB,SAAS,KAAK,YAAY,EAAO,MAC3B,CACN,EAAQ,MAAQ,KAId,MAAmB,CACnB,CAAC,GAAO,EAAM,UAAY,OAAS,CAAC,EAAM,UAC9C,EAAI,UAAW,GAAe,CACxB,aAAiB,EAAE,QACrB,EAAI,YAAY,EAAM,EAExB,CACF,EAAM,QAAQ,QAAS,GAAW,CAChC,IAAM,EAAgB,EAAE,OAAO,CAAC,EAAO,IAAK,EAAO,IAAI,CAAC,CACpD,EAAO,QACT,EAAc,UAAU,EAAO,MAAM,CACrC,EAAc,GAAG,QAAU,GAAe,CACxC,EAAK,cAAe,EAAQ,EAAM,EAClC,EAEJ,EAAc,MAAM,EAAI,EACxB,GAGE,EAAkB,GAAc,CAChC,CAAC,GAAQ,EAAM,UAAY,QAAU,CAAC,EAAM,SAChD,EAAM,QAAQ,QAAS,GAAW,CAChC,IAAM,EAAa,IAAK,OAAe,KAAK,OAAO,CACjD,SAAU,CAAC,EAAO,IAAK,EAAO,IAAI,CAClC,MAAO,EAAO,OAAS,GACxB,CAAC,CACF,GAAI,EAAO,MAAO,CAChB,IAAM,EAAa,IAAK,OAAe,KAAK,WAAW,CACrD,QAAS,EAAO,MAChB,OAAQ,IAAK,OAAe,KAAK,MAAM,EAAG,IAAI,CAC/C,CAAC,CACF,EAAW,GAAG,YAAe,CAC3B,EAAW,KAAK,EAAM,EAAW,aAAa,CAAC,CAC/C,EAAK,cAAe,EAAQ,KAAK,EACjC,CAEJ,EAAW,OAAO,EAAK,EACvB,SAGJ,MACQ,EAAM,YACN,CACA,GAAO,EAAM,UAAY,OAAO,GAAY,EAElD,CAAE,KAAM,GAAM,CACf,CAED,MACQ,EAAM,QACZ,MAAO,EAAS,IAAY,CACtB,IAAY,GACZ,IACF,EAAI,QAAQ,CACZ,EAAM,KACN,EAAQ,MAAQ,GAChB,MAAM,GAAU,CACZ,IAAY,QAAU,EAAM,QAAS,MAAM,GAAU,CACpD,MAAM,GAAY,GAG5B,CAED,EACE,KAAO,EAAM,WAAc,EAAM,KAAK,KAChC,CACA,GAAK,EAAI,QAAQ,EAAM,OAAQ,EAAM,KAAK,EAEhD,CAAE,KAAM,GAAM,CACf,CAED,EAAU,SAAY,CACpB,MAAM,GAAU,CACZ,EAAM,UAAY,QAAU,EAAM,QAAS,MAAM,GAAU,CAC1D,MAAM,GAAY,EACvB,CAEF,MAAkB,CAChB,AAEE,KADA,EAAI,QAAQ,CACN,OAER,aAhMA,EASM,MATN,EASM,CARJ,EAIO,MAAA,SAHD,eAAJ,IAAI,EACJ,MAAM,gBACL,MAAK,EAAA,CAAA,OAAYA,EAAAA,OAAM,CAAA,UAEf,EAAA,OAAA,GAAA,CAAX,EAEM,MAFN,EAEM,CADJ,EAAsB,EAAA,EAAA,CAAA,CAAf,KAAK,QAAO,CAAA,CAAA,CAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"C_Map2.js","names":["height"],"sources":["../src/components/C_Map/data.ts","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue","../src/components/C_Map/index.vue"],"sourcesContent":["export const MAP_TYPES = [\r\n { label: \"OpenStreetMap\", value: \"osm\" },\r\n { label: \"高德地图\", value: \"amap\" },\r\n] as const;\r\n\r\nexport type MapType = (typeof MAP_TYPES)[number][\"value\"];\r\n\r\nexport interface MapMarker {\r\n lat: number;\r\n lng: number;\r\n popup?: string;\r\n}\r\n\r\nexport interface MapConfig {\r\n height?: string;\r\n center?: [number, number];\r\n zoom?: number;\r\n markers?: MapMarker[];\r\n mapType?: MapType;\r\n amapKey?: string;\r\n}\r\n\r\nexport const DEFAULT_MAP_CONFIG: Required<\r\n Omit<MapConfig, \"markers\" | \"amapKey\">\r\n> = {\r\n height: \"400px\",\r\n center: [39.9042, 116.4074],\r\n zoom: 10,\r\n mapType: \"osm\",\r\n};\r\n\r\nexport const OSM_TILE_CONFIG = {\r\n url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\",\r\n attribution: \"© OpenStreetMap contributors\",\r\n maxZoom: 19,\r\n minZoom: 1,\r\n tileSize: 256,\r\n detectRetina: true,\r\n} as const;\r\n\r\nexport const AMAP_CONFIG = {\r\n apiUrl: \"https://webapi.amap.com/maps?v=2.0&key=\",\r\n note: \"高德地图需要API Key,如需使用请申请:https://lbs.amap.com/api/javascript-api/guide/create/\",\r\n} as const;\r\n\r\nexport const MAP_ICONS = {\r\n iconRetinaUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon-2x.png\",\r\n iconUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-icon.png\",\r\n shadowUrl:\r\n \"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png\",\r\n} as const;\r\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-12-02\n * @Description: 地图组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-map\">\n <div\n ref=\"mapContainer\"\n class=\"map-container\"\n :style=\"{ height: height }\"\n ></div>\n <div v-if=\"loading\" class=\"map-loading\">\n <NSpin size=\"large\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onMounted, onUnmounted } from \"vue\";\nimport { NSpin } from \"naive-ui\";\nimport L from \"leaflet\";\nimport \"leaflet/dist/leaflet.css\";\nimport { OSM_TILE_CONFIG, AMAP_CONFIG, MAP_ICONS } from \"./data\";\n\ndefineOptions({ name: \"C_Map\" });\n\ndelete (L.Icon.Default.prototype as any)._getIconUrl;\nL.Icon.Default.mergeOptions(MAP_ICONS);\n\ninterface MapMarker {\n lat: number;\n lng: number;\n popup?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n height?: string;\n center?: [number, number];\n zoom?: number;\n markers?: MapMarker[];\n mapType?: \"osm\" | \"amap\";\n amapKey?: string;\n }>(),\n {\n height: \"400px\",\n center: () => [39.9042, 116.4074],\n zoom: 10,\n markers: () => [],\n mapType: \"osm\",\n amapKey: \"\",\n },\n);\n\nconst emit = defineEmits<{\n ready: [map: any];\n markerClick: [marker: MapMarker, event: any];\n}>();\n\nconst mapContainer = ref<HTMLElement>();\nconst loading = ref(true);\nlet map: any = null;\n\nconst initOSMMap = async () => {\n if (!mapContainer.value) return;\n try {\n mapContainer.value.innerHTML = \"\";\n map = L.map(mapContainer.value, {\n center: props.center,\n zoom: props.zoom,\n zoomControl: true,\n preferCanvas: true,\n });\n const tileLayer = L.tileLayer(OSM_TILE_CONFIG.url, OSM_TILE_CONFIG);\n tileLayer.addTo(map);\n addMarkers();\n await nextTick();\n requestAnimationFrame(() => {\n map?.invalidateSize({ reset: true, pan: false });\n });\n loading.value = false;\n emit(\"ready\", map);\n } catch (error) {\n console.error(\"OpenStreetMap初始化失败:\", error);\n loading.value = false;\n }\n};\n\nconst initAMap = async () => {\n if (!mapContainer.value || !props.amapKey) return;\n try {\n mapContainer.value.innerHTML = \"\";\n const script = document.createElement(\"script\");\n script.type = \"text/javascript\";\n script.src = `${AMAP_CONFIG.apiUrl}${props.amapKey}`;\n script.onload = () => {\n if ((window as any).AMap) {\n const amap = new (window as any).AMap.Map(mapContainer.value, {\n zoom: props.zoom,\n center: props.center,\n });\n addAMapMarkers(amap);\n loading.value = false;\n emit(\"ready\", amap);\n }\n };\n script.onerror = () => {\n loading.value = false;\n };\n document.head.appendChild(script);\n } catch {\n loading.value = false;\n }\n};\n\nconst addMarkers = () => {\n if (!map || props.mapType !== \"osm\" || !props.markers) return;\n map.eachLayer((layer: any) => {\n if (layer instanceof L.Marker) {\n map.removeLayer(layer);\n }\n });\n props.markers.forEach((marker) => {\n const leafletMarker = L.marker([marker.lat, marker.lng]);\n if (marker.popup) {\n leafletMarker.bindPopup(marker.popup);\n leafletMarker.on(\"click\", (event: any) => {\n emit(\"markerClick\", marker, event);\n });\n }\n leafletMarker.addTo(map);\n });\n};\n\nconst addAMapMarkers = (amap: any) => {\n if (!amap || props.mapType !== \"amap\" || !props.markers) return;\n props.markers.forEach((marker) => {\n const amapMarker = new (window as any).AMap.Marker({\n position: [marker.lat, marker.lng],\n title: marker.popup || \"\",\n });\n if (marker.popup) {\n const infoWindow = new (window as any).AMap.InfoWindow({\n content: marker.popup,\n offset: new (window as any).AMap.Pixel(0, -30),\n });\n amapMarker.on(\"click\", () => {\n infoWindow.open(amap, amapMarker.getPosition());\n emit(\"markerClick\", marker, null);\n });\n }\n amapMarker.setMap(amap);\n });\n};\n\nwatch(\n () => props.markers,\n () => {\n if (map && props.mapType === \"osm\") addMarkers();\n },\n { deep: true },\n);\n\nwatch(\n () => props.mapType,\n async (newType, oldType) => {\n if (newType === oldType) return;\n if (map) {\n map.remove();\n map = null;\n loading.value = true;\n await nextTick();\n if (newType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n }\n },\n);\n\nwatch(\n [() => props.center, () => props.zoom],\n () => {\n if (map) map.setView(props.center, props.zoom);\n },\n { deep: true },\n);\n\nonMounted(async () => {\n await nextTick();\n if (props.mapType === \"amap\" && props.amapKey) await initAMap();\n else await initOSMMap();\n});\n\nonUnmounted(() => {\n if (map) {\n map.remove();\n map = null;\n }\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"+WAAA,MAAa,EAAY,CACvB,CAAE,MAAO,gBAAiB,MAAO,MAAO,CACxC,CAAE,MAAO,OAAQ,MAAO,OAAQ,CACjC,CAmBY,EAET,CACF,OAAQ,QACR,OAAQ,CAAC,QAAS,SAAS,CAC3B,KAAM,GACN,QAAS,MACV,CAEY,EAAkB,CAC7B,IAAK,qDACL,YAAa,+BACb,QAAS,GACT,QAAS,EACT,SAAU,IACV,aAAc,GACf,CAEY,EAAc,CACzB,OAAQ,0CACR,KAAM,8EACP,CAEY,EAAY,CACvB,cACE,iFACF,QACE,8EACF,UACE,gFACH,ySGvBD,OAAQ,EAAE,KAAK,QAAQ,UAAkB,YACzC,EAAE,KAAK,QAAQ,aAAa,EAAU,CAQtC,IAAM,EAAQ,EAmBR,EAAO,EAKP,EAAe,GAAkB,CACjC,EAAU,EAAI,GAAK,CACrB,EAAW,KAET,EAAa,SAAY,CACxB,KAAa,MAClB,GAAI,CACF,EAAa,MAAM,UAAY,GAC/B,EAAM,EAAE,IAAI,EAAa,MAAO,CAC9B,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,YAAa,GACb,aAAc,GACf,CAAC,CACgB,EAAE,UAAU,EAAgB,IAAK,EAAgB,CACzD,MAAM,EAAI,CACpB,GAAY,CACZ,MAAM,GAAU,CAChB,0BAA4B,CAC1B,GAAK,eAAe,CAAE,MAAO,GAAM,IAAK,GAAO,CAAC,EAChD,CACF,EAAQ,MAAQ,GAChB,EAAK,QAAS,EAAI,OACX,EAAO,CACd,QAAQ,MAAM,sBAAuB,EAAM,CAC3C,EAAQ,MAAQ,KAId,EAAW,SAAY,CACvB,MAAC,EAAa,OAAS,CAAC,EAAM,SAClC,GAAI,CACF,EAAa,MAAM,UAAY,GAC/B,IAAM,EAAS,SAAS,cAAc,SAAS,CAC/C,EAAO,KAAO,kBACd,EAAO,IAAM,GAAG,EAAY,SAAS,EAAM,UAC3C,EAAO,WAAe,CACpB,GAAK,OAAe,KAAM,CACxB,IAAM,EAAO,IAAK,OAAe,KAAK,IAAI,EAAa,MAAO,CAC5D,KAAM,EAAM,KACZ,OAAQ,EAAM,OACf,CAAC,CACF,EAAe,EAAK,CACpB,EAAQ,MAAQ,GAChB,EAAK,QAAS,EAAK,GAGvB,EAAO,YAAgB,CACrB,EAAQ,MAAQ,IAElB,SAAS,KAAK,YAAY,EAAO,MAC3B,CACN,EAAQ,MAAQ,KAId,MAAmB,CACnB,CAAC,GAAO,EAAM,UAAY,OAAS,CAAC,EAAM,UAC9C,EAAI,UAAW,GAAe,CACxB,aAAiB,EAAE,QACrB,EAAI,YAAY,EAAM,EAExB,CACF,EAAM,QAAQ,QAAS,GAAW,CAChC,IAAM,EAAgB,EAAE,OAAO,CAAC,EAAO,IAAK,EAAO,IAAI,CAAC,CACpD,EAAO,QACT,EAAc,UAAU,EAAO,MAAM,CACrC,EAAc,GAAG,QAAU,GAAe,CACxC,EAAK,cAAe,EAAQ,EAAM,EAClC,EAEJ,EAAc,MAAM,EAAI,EACxB,GAGE,EAAkB,GAAc,CAChC,CAAC,GAAQ,EAAM,UAAY,QAAU,CAAC,EAAM,SAChD,EAAM,QAAQ,QAAS,GAAW,CAChC,IAAM,EAAa,IAAK,OAAe,KAAK,OAAO,CACjD,SAAU,CAAC,EAAO,IAAK,EAAO,IAAI,CAClC,MAAO,EAAO,OAAS,GACxB,CAAC,CACF,GAAI,EAAO,MAAO,CAChB,IAAM,EAAa,IAAK,OAAe,KAAK,WAAW,CACrD,QAAS,EAAO,MAChB,OAAQ,IAAK,OAAe,KAAK,MAAM,EAAG,IAAI,CAC/C,CAAC,CACF,EAAW,GAAG,YAAe,CAC3B,EAAW,KAAK,EAAM,EAAW,aAAa,CAAC,CAC/C,EAAK,cAAe,EAAQ,KAAK,EACjC,CAEJ,EAAW,OAAO,EAAK,EACvB,SAGJ,MACQ,EAAM,YACN,CACA,GAAO,EAAM,UAAY,OAAO,GAAY,EAElD,CAAE,KAAM,GAAM,CACf,CAED,MACQ,EAAM,QACZ,MAAO,EAAS,IAAY,CACtB,IAAY,GACZ,IACF,EAAI,QAAQ,CACZ,EAAM,KACN,EAAQ,MAAQ,GAChB,MAAM,GAAU,CACZ,IAAY,QAAU,EAAM,QAAS,MAAM,GAAU,CACpD,MAAM,GAAY,GAG5B,CAED,EACE,KAAO,EAAM,WAAc,EAAM,KAAK,KAChC,CACA,GAAK,EAAI,QAAQ,EAAM,OAAQ,EAAM,KAAK,EAEhD,CAAE,KAAM,GAAM,CACf,CAED,EAAU,SAAY,CACpB,MAAM,GAAU,CACZ,EAAM,UAAY,QAAU,EAAM,QAAS,MAAM,GAAU,CAC1D,MAAM,GAAY,EACvB,CAEF,MAAkB,CAChB,AAEE,KADA,EAAI,QAAQ,CACN,OAER,aAhMA,EASM,MATN,EASM,CARJ,EAIO,MAAA,SAHD,eAAJ,IAAI,EACJ,MAAM,gBACL,MAAK,EAAA,CAAA,OAAYA,EAAAA,OAAM,CAAA,UAEf,EAAA,OAAA,GAAA,CAAX,EAEM,MAFN,EAEM,CADJ,EAAsB,EAAA,EAAA,CAAA,CAAf,KAAK,QAAO,CAAA,CAAA,CAAA,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown-
|
|
1
|
+
{"version":3,"file":"C_Markdown-Kujzx1qG.css","names":[],"sources":["../src/components/C_Markdown/index.vue?vue&type=style&index=0&scoped=b64c492a&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */\n.c-markdown-wrapper[data-v-b64c492a] {\n position: relative;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {\n border-radius: 6px;\n border: 1px solid var(--c-border);\n background-color: var(--c-bg-card);\n /* 禁用状态样式 */\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {\n border-color: var(--c-primary);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {\n border-color: var(--c-primary);\n box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {\n background-color: var(--c-bg-disabled, #fafafc);\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {\n background-color: var(--c-bg-card);\n border-bottom: 1px solid var(--c-border);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {\n color: var(--c-text-1);\n caret-color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {\n background-color: var(--c-bg-card);\n border-left: 1px solid var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {\n color: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {\n background-color: rgba(255, 255, 255, 0.12);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n opacity: 0.9;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {\n opacity: 1;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {\n background-color: transparent;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {\n background-color: var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {\n background-color: rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {\n background-color: rgba(255, 255, 255, 0.3);\n}\n.c-markdown-wrapper .word-count[data-v-b64c492a] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 12px;\n color: var(--c-text-4);\n background: var(--c-bg-card);\n padding: 2px 6px;\n border-radius: 4px;\n z-index: 10;\n}\n.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {\n color: var(--c-error);\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown-
|
|
1
|
+
{"version":3,"file":"C_Markdown-YCAmBbNF.css","names":[],"sources":["../src/components/C_Markdown/index.vue?vue&type=style&index=0&scoped=b64c492a&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */\n.c-markdown-wrapper[data-v-b64c492a] {\n position: relative;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {\n border-radius: 6px;\n border: 1px solid var(--c-border);\n background-color: var(--c-bg-card);\n /* 禁用状态样式 */\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {\n border-color: var(--c-primary);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {\n border-color: var(--c-primary);\n box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {\n background-color: var(--c-bg-disabled, #fafafc);\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {\n cursor: not-allowed;\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {\n background-color: var(--c-bg-card);\n border-bottom: 1px solid var(--c-border);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {\n color: var(--c-text-1);\n caret-color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {\n background-color: var(--c-bg-card);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {\n background-color: var(--c-bg-card);\n color: var(--c-text-1);\n}\n.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {\n background-color: var(--c-bg-card);\n border-left: 1px solid var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {\n color: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {\n background-color: rgba(255, 255, 255, 0.12);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n opacity: 0.9;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {\n opacity: 1;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {\n background-color: transparent;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {\n fill: #ffffff;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {\n background-color: rgba(255, 255, 255, 0.08);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {\n background-color: var(--c-border);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {\n background-color: rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n}\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,\n.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {\n background-color: rgba(255, 255, 255, 0.3);\n}\n.c-markdown-wrapper .word-count[data-v-b64c492a] {\n position: absolute;\n bottom: 8px;\n right: 12px;\n font-size: 12px;\n color: var(--c-text-4);\n background: var(--c-bg-card);\n padding: 2px 6px;\n border-radius: 4px;\n z-index: 10;\n}\n.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {\n color: var(--c-error);\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_Markdown.css
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
1
|
/* unplugin-vue-components disabled *//* C_Markdown 组件样式文件 */
|
|
2
|
-
.c-markdown-wrapper[data-v-
|
|
2
|
+
.c-markdown-wrapper[data-v-b64c492a] {
|
|
3
3
|
position: relative;
|
|
4
4
|
}
|
|
5
|
-
.c-markdown-wrapper[data-v-
|
|
5
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor {
|
|
6
6
|
border-radius: 6px;
|
|
7
7
|
border: 1px solid var(--c-border);
|
|
8
8
|
background-color: var(--c-bg-card);
|
|
9
9
|
/* 禁用状态样式 */
|
|
10
10
|
}
|
|
11
|
-
.c-markdown-wrapper[data-v-
|
|
11
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:hover {
|
|
12
12
|
border-color: var(--c-primary);
|
|
13
13
|
}
|
|
14
|
-
.c-markdown-wrapper[data-v-
|
|
14
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor:focus-within {
|
|
15
15
|
border-color: var(--c-primary);
|
|
16
16
|
box-shadow: 0 0 0 2px var(--c-primary-opacity, rgba(24, 160, 88, 0.2));
|
|
17
17
|
}
|
|
18
|
-
.c-markdown-wrapper[data-v-
|
|
18
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled {
|
|
19
19
|
background-color: var(--c-bg-disabled, #fafafc);
|
|
20
20
|
cursor: not-allowed;
|
|
21
21
|
}
|
|
22
|
-
.c-markdown-wrapper[data-v-
|
|
22
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor.disabled .v-md-editor__editor {
|
|
23
23
|
cursor: not-allowed;
|
|
24
24
|
}
|
|
25
|
-
.c-markdown-wrapper[data-v-
|
|
25
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar {
|
|
26
26
|
background-color: var(--c-bg-card);
|
|
27
27
|
border-bottom: 1px solid var(--c-border);
|
|
28
28
|
}
|
|
29
|
-
.c-markdown-wrapper[data-v-
|
|
29
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor-wrapper {
|
|
30
30
|
background-color: var(--c-bg-card);
|
|
31
31
|
}
|
|
32
|
-
.c-markdown-wrapper[data-v-
|
|
32
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor {
|
|
33
33
|
background-color: var(--c-bg-card);
|
|
34
34
|
color: var(--c-text-1);
|
|
35
35
|
}
|
|
36
|
-
.c-markdown-wrapper[data-v-
|
|
36
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__editor textarea {
|
|
37
37
|
color: var(--c-text-1);
|
|
38
38
|
caret-color: var(--c-text-1);
|
|
39
39
|
}
|
|
40
|
-
.c-markdown-wrapper[data-v-
|
|
40
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview-wrapper {
|
|
41
41
|
background-color: var(--c-bg-card);
|
|
42
42
|
}
|
|
43
|
-
.c-markdown-wrapper[data-v-
|
|
43
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__preview {
|
|
44
44
|
background-color: var(--c-bg-card);
|
|
45
45
|
color: var(--c-text-1);
|
|
46
46
|
}
|
|
47
|
-
.c-markdown-wrapper[data-v-
|
|
47
|
+
.c-markdown-wrapper[data-v-b64c492a] .v-md-editor .v-md-editor__toc-nav-wrapper {
|
|
48
48
|
background-color: var(--c-bg-card);
|
|
49
49
|
border-left: 1px solid var(--c-border);
|
|
50
50
|
}
|
|
51
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
51
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item {
|
|
52
52
|
color: #ffffff;
|
|
53
53
|
}
|
|
54
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
54
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover {
|
|
55
55
|
background-color: rgba(255, 255, 255, 0.08);
|
|
56
56
|
}
|
|
57
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
57
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item.is-active {
|
|
58
58
|
background-color: rgba(255, 255, 255, 0.12);
|
|
59
59
|
}
|
|
60
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
60
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item svg {
|
|
61
61
|
fill: #ffffff;
|
|
62
62
|
opacity: 0.9;
|
|
63
63
|
}
|
|
64
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
64
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-item:hover svg {
|
|
65
65
|
opacity: 1;
|
|
66
66
|
}
|
|
67
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
67
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item {
|
|
68
68
|
background-color: transparent;
|
|
69
69
|
}
|
|
70
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
70
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item svg {
|
|
71
71
|
fill: #ffffff;
|
|
72
72
|
}
|
|
73
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
73
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-right .v-md-editor__toolbar-item:hover {
|
|
74
74
|
background-color: rgba(255, 255, 255, 0.08);
|
|
75
75
|
}
|
|
76
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
76
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__toolbar-divider {
|
|
77
77
|
background-color: var(--c-border);
|
|
78
78
|
}
|
|
79
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
80
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
79
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar,
|
|
80
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar {
|
|
81
81
|
width: 8px;
|
|
82
82
|
height: 8px;
|
|
83
83
|
}
|
|
84
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
85
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
84
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-track,
|
|
85
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-track {
|
|
86
86
|
background-color: rgba(255, 255, 255, 0.05);
|
|
87
87
|
}
|
|
88
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
89
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
88
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb,
|
|
89
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb {
|
|
90
90
|
background-color: rgba(255, 255, 255, 0.2);
|
|
91
91
|
border-radius: 4px;
|
|
92
92
|
}
|
|
93
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
94
|
-
.c-markdown-wrapper.is-dark[data-v-
|
|
93
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__editor::-webkit-scrollbar-thumb:hover,
|
|
94
|
+
.c-markdown-wrapper.is-dark[data-v-b64c492a] .v-md-editor .v-md-editor__preview::-webkit-scrollbar-thumb:hover {
|
|
95
95
|
background-color: rgba(255, 255, 255, 0.3);
|
|
96
96
|
}
|
|
97
|
-
.c-markdown-wrapper .word-count[data-v-
|
|
97
|
+
.c-markdown-wrapper .word-count[data-v-b64c492a] {
|
|
98
98
|
position: absolute;
|
|
99
99
|
bottom: 8px;
|
|
100
100
|
right: 12px;
|
|
@@ -105,8 +105,8 @@
|
|
|
105
105
|
border-radius: 4px;
|
|
106
106
|
z-index: 10;
|
|
107
107
|
}
|
|
108
|
-
.c-markdown-wrapper .word-count.exceed[data-v-
|
|
108
|
+
.c-markdown-wrapper .word-count.exceed[data-v-b64c492a] {
|
|
109
109
|
color: var(--c-error);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
/*# sourceMappingURL=C_Markdown-
|
|
112
|
+
/*# sourceMappingURL=C_Markdown-Kujzx1qG.css.map*/
|
package/dist/C_Markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"8hCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,GAAA,EAAA,EAAA,KAAqB,KAAK,CAC1B,GAAA,EAAA,EAAA,KAAiB,GAAG,CAEpB,GAAA,EAAA,EAAA,cACG,EAAM,YAAY,QAAU,EACnC,CAEI,GAAA,EAAA,EAAA,cAA2C,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACX,CACD,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAmB,CAChD,GACJ,EAEF,EAAA,EAAA,eAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAO,EAEpD,EAEF,EAAA,EAAA,WACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAE,EAGpD,CAAE,UAAW,GAAM,CACpB,CAED,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAU,CAC1D,OAEF,EAAK,oBAAqB,EAAM,CAC5B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAO,EAIrC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAK,CACtB,EAAM,UACR,EAAS,EAAK,EAIZ,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAK,EAGpB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAM,EAG3C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAa,EAGnC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAK,EAG7B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAc,CAC9C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAK,EACtB,EAAM,iBAAiB,SAkB5B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAO,EAgBxB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAE,EAOH,YACD,CAAC,oDArLI,MAAA,CAzBJ,OAAA,EAAA,EAAA,gBAAK,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAuBzB,EAAA,QAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|
|
1
|
+
{"version":3,"file":"C_Markdown.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"8hCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,GAAA,EAAA,EAAA,KAAqB,KAAI,CACzB,GAAA,EAAA,EAAA,KAAiB,GAAE,CAEnB,GAAA,EAAA,EAAA,cACG,EAAM,YAAY,QAAU,EACpC,CAEK,GAAA,EAAA,EAAA,cAA2C,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACZ,CACA,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAkB,CAC/C,GACL,EAED,EAAA,EAAA,eAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAM,EAEpD,EAED,EAAA,EAAA,WACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAC,EAGnD,CAAE,UAAW,GAAK,CACpB,CAEA,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAS,CACzD,OAEF,EAAK,oBAAqB,EAAK,CAC3B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAM,EAIpC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAI,CACrB,EAAM,UACR,EAAS,EAAI,EAIX,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAI,EAGnB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAK,EAG1C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAY,EAGlC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAI,EAG5B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAa,CAC7C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAI,EACrB,EAAM,iBAAgB,SAkB3B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAM,EAgBvB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAC,EAOF,YACD,CAAA,oDArLK,MAAA,CAzBJ,OAAA,EAAA,EAAA,gBAAK,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,EAAA,cAAA,EAAA,EAAA,OAuBzB,EAAA,QAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|
package/dist/C_Markdown2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./export-helper.js";import{computed as t,createElementBlock as n,createVNode as r,defineComponent as i,normalizeClass as a,onMounted as o,openBlock as s,ref as c,unref as l,watch as u}from"vue";import d from"@kangc/v-md-editor";var f=e(i({name:`C_Markdown`,__name:`index`,props:{modelValue:{default:``},height:{default:`400px`},disabled:{type:Boolean,default:!1},placeholder:{default:`请输入 Markdown 内容...`},mode:{default:`editable`},toolbar:{},uploadImageConfig:{},tocNavPosition:{default:`right`},defaultFullscreen:{type:Boolean,default:!1},autofocus:{type:Boolean,default:!1},includeLevel:{default:()=>[1,2,3,4,5,6]},leftToolbar:{default:`undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save`},rightToolbar:{default:`preview toc sync-scroll fullscreen`},maxLength:{default:5e4},showWordCount:{type:Boolean,default:!0},autoSave:{type:Boolean,default:!1},autoSaveInterval:{default:3e4},isDark:{type:Boolean,default:!1}},emits:[`update:modelValue`,`change`,`save`,`upload-image`,`fullscreen-change`,`copy-code-success`,`word-count-change`,`auto-save`,`max-length-exceeded`],setup(e,{expose:i,emit:f}){let p=e,m=f,h=c(null),g=c(``),_=t(()=>p.modelValue?.length||0),v=t(()=>{let e={accept:`image/*`,multiple:!1};return p.uploadImageConfig?{...e,...p.uploadImageConfig}:e});o(()=>{p.showWordCount&&p.modelValue&&m(`word-count-change`,p.modelValue.length)}),u(()=>p.modelValue,e=>{p.showWordCount&&m(`word-count-change`,e?.length||0)},{immediate:!0});let y=e=>{if(e.length>p.maxLength){m(`max-length-exceeded`,e.length,p.maxLength);return}m(`update:modelValue`,e),p.showWordCount&&m(`word-count-change`,e.length)},b=(e,t)=>{g.value=t,m(`change`,e,t),p.autoSave&&E(e)},x=(e,t)=>{m(`save`,e,t)},S=(e,t,n)=>{m(`upload-image`,e,t,n)},C=e=>{m(`fullscreen-change`,e)},w=e=>{m(`copy-code-success`,e)},T=null,E=e=>{T&&clearTimeout(T),T=setTimeout(()=>{m(`auto-save`,e)},p.autoSaveInterval)};return i({focus:()=>{h.value?.focus()},getHtml:()=>g.value,insertText:e=>{h.value?.insert(t=>({text:`${t}${e}`,selected:e}))},wordCount:_}),(e,t)=>(s(),n(`div`,{class:a([`c-markdown-wrapper`,{"is-dark":e.isDark}])},[r(l(d),{ref_key:`editorRef`,ref:h,"model-value":e.modelValue,height:e.height,placeholder:e.placeholder,toolbar:e.toolbar,mode:e.mode,"upload-image-config":v.value,"toc-nav-position":e.tocNavPosition,"default-fullscreen":e.defaultFullscreen,autofocus:e.autofocus,"include-level":e.includeLevel,"left-toolbar":e.leftToolbar,"right-toolbar":e.rightToolbar,"default-show-toc":!0,"onUpdate:modelValue":y,onChange:b,onSave:x,onUploadImage:S,onFullscreenChange:C,onCopyCodeSuccess:w},null,8,[`model-value`,`height`,`placeholder`,`toolbar`,`mode`,`upload-image-config`,`toc-nav-position`,`default-fullscreen`,`autofocus`,`include-level`,`left-toolbar`,`right-toolbar`])],2))}}),[[`__scopeId`,`data-v-
|
|
1
|
+
import{t as e}from"./export-helper.js";import{computed as t,createElementBlock as n,createVNode as r,defineComponent as i,normalizeClass as a,onMounted as o,openBlock as s,ref as c,unref as l,watch as u}from"vue";import d from"@kangc/v-md-editor";var f=e(i({name:`C_Markdown`,__name:`index`,props:{modelValue:{default:``},height:{default:`400px`},disabled:{type:Boolean,default:!1},placeholder:{default:`请输入 Markdown 内容...`},mode:{default:`editable`},toolbar:{},uploadImageConfig:{},tocNavPosition:{default:`right`},defaultFullscreen:{type:Boolean,default:!1},autofocus:{type:Boolean,default:!1},includeLevel:{default:()=>[1,2,3,4,5,6]},leftToolbar:{default:`undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save`},rightToolbar:{default:`preview toc sync-scroll fullscreen`},maxLength:{default:5e4},showWordCount:{type:Boolean,default:!0},autoSave:{type:Boolean,default:!1},autoSaveInterval:{default:3e4},isDark:{type:Boolean,default:!1}},emits:[`update:modelValue`,`change`,`save`,`upload-image`,`fullscreen-change`,`copy-code-success`,`word-count-change`,`auto-save`,`max-length-exceeded`],setup(e,{expose:i,emit:f}){let p=e,m=f,h=c(null),g=c(``),_=t(()=>p.modelValue?.length||0),v=t(()=>{let e={accept:`image/*`,multiple:!1};return p.uploadImageConfig?{...e,...p.uploadImageConfig}:e});o(()=>{p.showWordCount&&p.modelValue&&m(`word-count-change`,p.modelValue.length)}),u(()=>p.modelValue,e=>{p.showWordCount&&m(`word-count-change`,e?.length||0)},{immediate:!0});let y=e=>{if(e.length>p.maxLength){m(`max-length-exceeded`,e.length,p.maxLength);return}m(`update:modelValue`,e),p.showWordCount&&m(`word-count-change`,e.length)},b=(e,t)=>{g.value=t,m(`change`,e,t),p.autoSave&&E(e)},x=(e,t)=>{m(`save`,e,t)},S=(e,t,n)=>{m(`upload-image`,e,t,n)},C=e=>{m(`fullscreen-change`,e)},w=e=>{m(`copy-code-success`,e)},T=null,E=e=>{T&&clearTimeout(T),T=setTimeout(()=>{m(`auto-save`,e)},p.autoSaveInterval)};return i({focus:()=>{h.value?.focus()},getHtml:()=>g.value,insertText:e=>{h.value?.insert(t=>({text:`${t}${e}`,selected:e}))},wordCount:_}),(e,t)=>(s(),n(`div`,{class:a([`c-markdown-wrapper`,{"is-dark":e.isDark}])},[r(l(d),{ref_key:`editorRef`,ref:h,"model-value":e.modelValue,height:e.height,placeholder:e.placeholder,toolbar:e.toolbar,mode:e.mode,"upload-image-config":v.value,"toc-nav-position":e.tocNavPosition,"default-fullscreen":e.defaultFullscreen,autofocus:e.autofocus,"include-level":e.includeLevel,"left-toolbar":e.leftToolbar,"right-toolbar":e.rightToolbar,"default-show-toc":!0,"onUpdate:modelValue":y,onChange:b,onSave:x,onUploadImage:S,onFullscreenChange:C,onCopyCodeSuccess:w},null,8,[`model-value`,`height`,`placeholder`,`toolbar`,`mode`,`upload-image-config`,`toc-nav-position`,`default-fullscreen`,`autofocus`,`include-level`,`left-toolbar`,`right-toolbar`])],2))}}),[[`__scopeId`,`data-v-b64c492a`]]);export{f as t};
|
|
2
2
|
//# sourceMappingURL=C_Markdown2.js.map
|
package/dist/C_Markdown2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Markdown2.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-20\r\n * @Description: Markdown 编辑器封装组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-markdown-wrapper\"\r\n :class=\"{ 'is-dark': isDark }\"\r\n >\r\n <VMdEditor\r\n ref=\"editorRef\"\r\n :model-value=\"modelValue\"\r\n :height=\"height\"\r\n :placeholder=\"placeholder\"\r\n :toolbar=\"toolbar\"\r\n :mode=\"mode\"\r\n :upload-image-config=\"computedUploadImageConfig\"\r\n :toc-nav-position=\"tocNavPosition\"\r\n :default-fullscreen=\"defaultFullscreen\"\r\n :autofocus=\"autofocus\"\r\n :include-level=\"includeLevel\"\r\n :left-toolbar=\"leftToolbar\"\r\n :right-toolbar=\"rightToolbar\"\r\n :default-show-toc=\"true\"\r\n @update:model-value=\"handleInput\"\r\n @change=\"handleChange\"\r\n @save=\"handleSave\"\r\n @upload-image=\"handleUploadImage\"\r\n @fullscreen-change=\"handleFullscreenChange\"\r\n @copy-code-success=\"handleCopyCodeSuccess\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, onMounted } from 'vue'\r\n import VMdEditor from '@kangc/v-md-editor'\r\n\r\n defineOptions({ name: 'C_Markdown' })\r\n\r\n export type InsertImageFunction = (config: {\r\n url: string\r\n desc?: string\r\n width?: string | number\r\n height?: string | number\r\n }) => void\r\n\r\n interface Props {\r\n modelValue?: string\r\n height?: string | number\r\n disabled?: boolean\r\n placeholder?: string\r\n mode?: 'edit' | 'editable' | 'preview'\r\n toolbar?: object\r\n uploadImageConfig?: {\r\n accept?: string\r\n multiple?: boolean\r\n [key: string]: any\r\n }\r\n tocNavPosition?: 'left' | 'right'\r\n defaultFullscreen?: boolean\r\n autofocus?: boolean\r\n includeLevel?: number[]\r\n leftToolbar?: string\r\n rightToolbar?: string\r\n maxLength?: number\r\n showWordCount?: boolean\r\n autoSave?: boolean\r\n autoSaveInterval?: number\r\n /** 是否为暗色主题(外部传入) */\r\n isDark?: boolean\r\n }\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n modelValue: '',\r\n height: '400px',\r\n disabled: false,\r\n placeholder: '请输入 Markdown 内容...',\r\n mode: 'editable',\r\n tocNavPosition: 'right',\r\n defaultFullscreen: false,\r\n autofocus: false,\r\n includeLevel: () => [1, 2, 3, 4, 5, 6],\r\n leftToolbar:\r\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\r\n rightToolbar: 'preview toc sync-scroll fullscreen',\r\n maxLength: 50000,\r\n showWordCount: true,\r\n autoSave: false,\r\n autoSaveInterval: 30000,\r\n isDark: false,\r\n })\r\n\r\n interface Emits {\r\n 'update:modelValue': [value: string]\r\n change: [text: string, html: string]\r\n save: [text: string, html: string]\r\n 'upload-image': [\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList,\r\n ]\r\n 'fullscreen-change': [isFullscreen: boolean]\r\n 'copy-code-success': [text: string]\r\n 'word-count-change': [count: number]\r\n 'auto-save': [text: string]\r\n 'max-length-exceeded': [currentLength: number, maxLength: number]\r\n }\r\n\r\n const emit = defineEmits<Emits>()\r\n\r\n const editorRef = ref<any>(null)\r\n const cachedHtml = ref('')\r\n\r\n const wordCount = computed(() => {\r\n return props.modelValue?.length || 0\r\n })\r\n\r\n const computedUploadImageConfig = computed(() => {\r\n const defaultConfig = {\r\n accept: 'image/*',\r\n multiple: false,\r\n }\r\n return props.uploadImageConfig\r\n ? { ...defaultConfig, ...props.uploadImageConfig }\r\n : defaultConfig\r\n })\r\n\r\n onMounted(() => {\r\n if (props.showWordCount && props.modelValue) {\r\n emit('word-count-change', props.modelValue.length)\r\n }\r\n })\r\n\r\n watch(\r\n () => props.modelValue,\r\n newValue => {\r\n if (props.showWordCount) {\r\n emit('word-count-change', newValue?.length || 0)\r\n }\r\n },\r\n { immediate: true }\r\n )\r\n\r\n const handleInput = (value: string) => {\r\n if (value.length > props.maxLength) {\r\n emit('max-length-exceeded', value.length, props.maxLength)\r\n return\r\n }\r\n emit('update:modelValue', value)\r\n if (props.showWordCount) {\r\n emit('word-count-change', value.length)\r\n }\r\n }\r\n\r\n const handleChange = (text: string, html: string) => {\r\n cachedHtml.value = html\r\n emit('change', text, html)\r\n if (props.autoSave) {\r\n autoSave(text)\r\n }\r\n }\r\n\r\n const handleSave = (text: string, html: string) => {\r\n emit('save', text, html)\r\n }\r\n\r\n const handleUploadImage = (\r\n event: Event,\r\n insertImage: InsertImageFunction,\r\n files: FileList\r\n ) => {\r\n emit('upload-image', event, insertImage, files)\r\n }\r\n\r\n const handleFullscreenChange = (isFullscreen: boolean) => {\r\n emit('fullscreen-change', isFullscreen)\r\n }\r\n\r\n const handleCopyCodeSuccess = (text: string) => {\r\n emit('copy-code-success', text)\r\n }\r\n\r\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\r\n\r\n const autoSave = (text: string) => {\r\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\r\n autoSaveTimer = setTimeout(() => {\r\n emit('auto-save', text)\r\n }, props.autoSaveInterval)\r\n }\r\n\r\n const focus = () => {\r\n editorRef.value?.focus()\r\n }\r\n\r\n const getHtml = (): string => {\r\n return cachedHtml.value\r\n }\r\n\r\n const insertText = (text: string) => {\r\n editorRef.value?.insert((selected: string) => ({\r\n text: `${selected}${text}`,\r\n selected: text,\r\n }))\r\n }\r\n\r\n defineExpose({\r\n focus,\r\n getHtml,\r\n insertText,\r\n wordCount,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"uoCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,EAAY,EAAS,KAAK,CAC1B,EAAa,EAAI,GAAG,CAEpB,EAAY,MACT,EAAM,YAAY,QAAU,EACnC,CAEI,EAA4B,MAAe,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACX,CACD,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAmB,CAChD,GACJ,CAEF,MAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAO,EAEpD,CAEF,MACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAE,EAGpD,CAAE,UAAW,GAAM,CACpB,CAED,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAU,CAC1D,OAEF,EAAK,oBAAqB,EAAM,CAC5B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAO,EAIrC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAK,CACtB,EAAM,UACR,EAAS,EAAK,EAIZ,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAK,EAGpB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAM,EAG3C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAa,EAGnC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAK,EAG7B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAc,CAC9C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAK,EACtB,EAAM,iBAAiB,SAkB5B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAO,EAgBxB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAE,EAOH,YACD,CAAC,aA/MF,EA0BM,MAAA,CAzBJ,MAAK,EAAA,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,CAE3B,EAqBE,EAAA,EAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|
|
1
|
+
{"version":3,"file":"C_Markdown2.js","names":["isDark","modelValue","height","placeholder","toolbar","mode","tocNavPosition","defaultFullscreen","autofocus","includeLevel","leftToolbar","rightToolbar"],"sources":["../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue","../src/components/C_Markdown/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-20\n * @Description: Markdown 编辑器封装组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n class=\"c-markdown-wrapper\"\n :class=\"{ 'is-dark': isDark }\"\n >\n <VMdEditor\n ref=\"editorRef\"\n :model-value=\"modelValue\"\n :height=\"height\"\n :placeholder=\"placeholder\"\n :toolbar=\"toolbar\"\n :mode=\"mode\"\n :upload-image-config=\"computedUploadImageConfig\"\n :toc-nav-position=\"tocNavPosition\"\n :default-fullscreen=\"defaultFullscreen\"\n :autofocus=\"autofocus\"\n :include-level=\"includeLevel\"\n :left-toolbar=\"leftToolbar\"\n :right-toolbar=\"rightToolbar\"\n :default-show-toc=\"true\"\n @update:model-value=\"handleInput\"\n @change=\"handleChange\"\n @save=\"handleSave\"\n @upload-image=\"handleUploadImage\"\n @fullscreen-change=\"handleFullscreenChange\"\n @copy-code-success=\"handleCopyCodeSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, onMounted } from 'vue'\n import VMdEditor from '@kangc/v-md-editor'\n\n defineOptions({ name: 'C_Markdown' })\n\n export type InsertImageFunction = (config: {\n url: string\n desc?: string\n width?: string | number\n height?: string | number\n }) => void\n\n interface Props {\n modelValue?: string\n height?: string | number\n disabled?: boolean\n placeholder?: string\n mode?: 'edit' | 'editable' | 'preview'\n toolbar?: object\n uploadImageConfig?: {\n accept?: string\n multiple?: boolean\n [key: string]: any\n }\n tocNavPosition?: 'left' | 'right'\n defaultFullscreen?: boolean\n autofocus?: boolean\n includeLevel?: number[]\n leftToolbar?: string\n rightToolbar?: string\n maxLength?: number\n showWordCount?: boolean\n autoSave?: boolean\n autoSaveInterval?: number\n /** 是否为暗色主题(外部传入) */\n isDark?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n modelValue: '',\n height: '400px',\n disabled: false,\n placeholder: '请输入 Markdown 内容...',\n mode: 'editable',\n tocNavPosition: 'right',\n defaultFullscreen: false,\n autofocus: false,\n includeLevel: () => [1, 2, 3, 4, 5, 6],\n leftToolbar:\n 'undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save',\n rightToolbar: 'preview toc sync-scroll fullscreen',\n maxLength: 50000,\n showWordCount: true,\n autoSave: false,\n autoSaveInterval: 30000,\n isDark: false,\n })\n\n interface Emits {\n 'update:modelValue': [value: string]\n change: [text: string, html: string]\n save: [text: string, html: string]\n 'upload-image': [\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList,\n ]\n 'fullscreen-change': [isFullscreen: boolean]\n 'copy-code-success': [text: string]\n 'word-count-change': [count: number]\n 'auto-save': [text: string]\n 'max-length-exceeded': [currentLength: number, maxLength: number]\n }\n\n const emit = defineEmits<Emits>()\n\n const editorRef = ref<any>(null)\n const cachedHtml = ref('')\n\n const wordCount = computed(() => {\n return props.modelValue?.length || 0\n })\n\n const computedUploadImageConfig = computed(() => {\n const defaultConfig = {\n accept: 'image/*',\n multiple: false,\n }\n return props.uploadImageConfig\n ? { ...defaultConfig, ...props.uploadImageConfig }\n : defaultConfig\n })\n\n onMounted(() => {\n if (props.showWordCount && props.modelValue) {\n emit('word-count-change', props.modelValue.length)\n }\n })\n\n watch(\n () => props.modelValue,\n newValue => {\n if (props.showWordCount) {\n emit('word-count-change', newValue?.length || 0)\n }\n },\n { immediate: true }\n )\n\n const handleInput = (value: string) => {\n if (value.length > props.maxLength) {\n emit('max-length-exceeded', value.length, props.maxLength)\n return\n }\n emit('update:modelValue', value)\n if (props.showWordCount) {\n emit('word-count-change', value.length)\n }\n }\n\n const handleChange = (text: string, html: string) => {\n cachedHtml.value = html\n emit('change', text, html)\n if (props.autoSave) {\n autoSave(text)\n }\n }\n\n const handleSave = (text: string, html: string) => {\n emit('save', text, html)\n }\n\n const handleUploadImage = (\n event: Event,\n insertImage: InsertImageFunction,\n files: FileList\n ) => {\n emit('upload-image', event, insertImage, files)\n }\n\n const handleFullscreenChange = (isFullscreen: boolean) => {\n emit('fullscreen-change', isFullscreen)\n }\n\n const handleCopyCodeSuccess = (text: string) => {\n emit('copy-code-success', text)\n }\n\n let autoSaveTimer: ReturnType<typeof setTimeout> | null = null\n\n const autoSave = (text: string) => {\n if (autoSaveTimer) clearTimeout(autoSaveTimer)\n autoSaveTimer = setTimeout(() => {\n emit('auto-save', text)\n }, props.autoSaveInterval)\n }\n\n const focus = () => {\n editorRef.value?.focus()\n }\n\n const getHtml = (): string => {\n return cachedHtml.value\n }\n\n const insertText = (text: string) => {\n editorRef.value?.insert((selected: string) => ({\n text: `${selected}${text}`,\n selected: text,\n }))\n }\n\n defineExpose({\n focus,\n getHtml,\n insertText,\n wordCount,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"uoCE4EE,IAAM,EAAQ,EAoCR,EAAO,EAEP,EAAY,EAAS,KAAI,CACzB,EAAa,EAAI,GAAE,CAEnB,EAAY,MACT,EAAM,YAAY,QAAU,EACpC,CAEK,EAA4B,MAAe,CAC/C,IAAM,EAAgB,CACpB,OAAQ,UACR,SAAU,GACZ,CACA,OAAO,EAAM,kBACT,CAAE,GAAG,EAAe,GAAG,EAAM,kBAAkB,CAC/C,GACL,CAED,MAAgB,CACV,EAAM,eAAiB,EAAM,YAC/B,EAAK,oBAAqB,EAAM,WAAW,OAAM,EAEpD,CAED,MACQ,EAAM,WACZ,GAAY,CACN,EAAM,eACR,EAAK,oBAAqB,GAAU,QAAU,EAAC,EAGnD,CAAE,UAAW,GAAK,CACpB,CAEA,IAAM,EAAe,GAAkB,CACrC,GAAI,EAAM,OAAS,EAAM,UAAW,CAClC,EAAK,sBAAuB,EAAM,OAAQ,EAAM,UAAS,CACzD,OAEF,EAAK,oBAAqB,EAAK,CAC3B,EAAM,eACR,EAAK,oBAAqB,EAAM,OAAM,EAIpC,GAAgB,EAAc,IAAiB,CACnD,EAAW,MAAQ,EACnB,EAAK,SAAU,EAAM,EAAI,CACrB,EAAM,UACR,EAAS,EAAI,EAIX,GAAc,EAAc,IAAiB,CACjD,EAAK,OAAQ,EAAM,EAAI,EAGnB,GACJ,EACA,EACA,IACG,CACH,EAAK,eAAgB,EAAO,EAAa,EAAK,EAG1C,EAA0B,GAA0B,CACxD,EAAK,oBAAqB,EAAY,EAGlC,EAAyB,GAAiB,CAC9C,EAAK,oBAAqB,EAAI,EAG5B,EAAsD,KAEpD,EAAY,GAAiB,CAC7B,GAAe,aAAa,EAAa,CAC7C,EAAgB,eAAiB,CAC/B,EAAK,YAAa,EAAI,EACrB,EAAM,iBAAgB,SAkB3B,EAAa,CACX,UAhBkB,CAClB,EAAU,OAAO,OAAM,EAgBvB,YAZO,EAAW,MAalB,WAVkB,GAAiB,CACnC,EAAU,OAAO,OAAQ,IAAsB,CAC7C,KAAM,GAAG,IAAW,IACpB,SAAU,EACX,EAAC,EAOF,YACD,CAAA,aA/MD,EA0BM,MAAA,CAzBJ,MAAK,EAAA,CAAC,qBAAoB,CAAA,UACLA,EAAAA,OAAM,CAAA,CAAA,CAAA,CAAA,CAE3B,EAqBE,EAAA,EAAA,CAAA,SApBI,YAAJ,IAAI,EACH,cAAaC,EAAAA,WACb,OAAQC,EAAAA,OACR,YAAaC,EAAAA,YACb,QAASC,EAAAA,QACT,KAAMC,EAAAA,KACN,sBAAqB,EAAA,MACrB,mBAAkBC,EAAAA,eAClB,qBAAoBC,EAAAA,kBACpB,UAAWC,EAAAA,UACX,gBAAeC,EAAAA,aACf,eAAcC,EAAAA,YACd,gBAAeC,EAAAA,aACf,mBAAkB,GAClB,sBAAoB,EACpB,SAAQ,EACR,OAAM,EACN,cAAc,EACd,mBAAmB,EACnB,kBAAmB"}
|