@robot-admin/naive-ui-components 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +48 -32
  2. package/dist/C_Breadcrumb.js.map +1 -1
  3. package/dist/C_Breadcrumb2.js.map +1 -1
  4. package/dist/C_Menu.js.map +1 -1
  5. package/dist/C_Menu2.js.map +1 -1
  6. package/dist/{C_Table-Dcam_tRs.css.map → C_Table-vZlcgH6x.css.map} +1 -1
  7. package/dist/{C_Table-tbUx-R4H.css.map → C_Table-wzAO43l0.css.map} +1 -1
  8. package/dist/C_Table.css +69 -69
  9. package/dist/C_Table.js.map +1 -1
  10. package/dist/C_Table2.js +1 -1
  11. package/dist/C_Table2.js.map +1 -1
  12. package/dist/{C_TagsView-DX3LecK1.css.map → C_TagsView-BsutyC3U.css.map} +1 -1
  13. package/dist/{C_TagsView-DqOTa8bL.css.map → C_TagsView-Crm7yWg9.css.map} +1 -1
  14. package/dist/C_TagsView.css +36 -36
  15. package/dist/C_TagsView.js.map +1 -1
  16. package/dist/C_TagsView2.js +1 -1
  17. package/dist/C_TagsView2.js.map +1 -1
  18. package/dist/constants.d.ts +3 -3
  19. package/dist/constants2.d.ts +5 -5
  20. package/dist/constants3.d.ts +2 -2
  21. package/dist/constants4.d.ts +6 -6
  22. package/dist/constants5.d.ts +2 -2
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/index11.vue.d.ts +4 -4
  26. package/dist/index12.vue.d.ts +2 -2
  27. package/dist/index13.vue.d.ts +5 -5
  28. package/dist/index15.vue.d.ts +1 -1
  29. package/dist/index17.vue.d.ts +1 -1
  30. package/dist/index19.vue.d.ts +3 -3
  31. package/dist/index2.vue.d.ts +1 -1
  32. package/dist/index4.vue.d.ts +4 -4
  33. package/dist/index5.vue.d.ts +2 -2
  34. package/dist/index6.vue.d.ts +2 -2
  35. package/dist/index7.vue.d.ts +1 -1
  36. package/dist/index8.vue.d.ts +1 -1
  37. package/dist/index9.vue.d.ts +3 -3
  38. package/dist/menuAdapter.js +1 -1
  39. package/dist/menuAdapter.js.map +1 -1
  40. package/dist/resolver.cjs.map +1 -1
  41. package/dist/resolver.js.map +1 -1
  42. package/dist/style.css +107 -107
  43. package/dist/useCollapsePanel.d.ts +3 -3
  44. package/dist/useCropperCore.d.ts +7 -7
  45. package/dist/useDraggableLayout.d.ts +2 -2
  46. package/dist/useDynamicFormState.d.ts +118 -118
  47. package/dist/useEdgeInteraction.d.ts +1 -1
  48. package/dist/useInfiniteScroll.d.ts +2 -2
  49. package/dist/useModalEdit.d.ts +0 -1
  50. package/dist/useQRCode.d.ts +2 -2
  51. package/dist/useSignatureHistory.d.ts +1 -1
  52. package/dist/useSplitResize.d.ts +2 -2
  53. package/dist/useTimeSelection.d.ts +2 -2
  54. package/dist/useTreeOperations.d.ts +3 -3
  55. package/dist/useWorkflowValidation.d.ts +3 -3
  56. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"C_TagsView2.js","names":[],"sources":["../src/components/C_TagsView/useTagsView.ts","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue"],"sourcesContent":["import { ref, type Ref } from 'vue'\nimport type { TagItem } from '../_shared'\n\nexport interface UseTagsViewOptions {\n /** localStorage 持久化 key,传空字符串则不持久化 */\n persistKey?: string\n /** 首页路径,用于 removeAll 后的回退 */\n homePath?: string\n}\n\nconst STORAGE_KEY_DEFAULT = '__tags_view_list__'\n\n/**\n * 标签页管理 composable\n *\n * 独立于组件使用 — 可在任何地方管理标签状态\n *\n * @example 独立使用\n * ```ts\n * const tags = useTagsView({ persistKey: 'my-tags' })\n * tags.addTag({ path: '/home', title: '首页', meta: { affix: true } })\n * ```\n */\nexport function useTagsView(options: UseTagsViewOptions = {}) {\n const { persistKey = STORAGE_KEY_DEFAULT, homePath = '/home' } = options\n\n // ====== 持久化 ======\n const loadPersistedTags = (): TagItem[] => {\n if (!persistKey) return []\n try {\n const raw = localStorage.getItem(persistKey)\n return raw ? JSON.parse(raw) : []\n } catch {\n return []\n }\n }\n\n const persistTags = (tags: TagItem[]) => {\n if (!persistKey) return\n try {\n localStorage.setItem(persistKey, JSON.stringify(tags))\n } catch {\n /* silently fail */\n }\n }\n\n // ====== State ======\n const tagsViewList: Ref<TagItem[]> = ref(loadPersistedTags())\n const activeTag = ref('')\n\n const syncPersist = () => persistTags(tagsViewList.value)\n\n // ====== Actions ======\n\n const initTags = (tags?: TagItem[]) => {\n if (tags) {\n tagsViewList.value = tags\n } else {\n // 去重\n tagsViewList.value = [\n ...new Map(tagsViewList.value.map(tag => [tag.path, tag])).values(),\n ]\n }\n syncPersist()\n }\n\n const setActiveTag = (path: string) => {\n activeTag.value = path\n }\n\n const addTag = (tag: TagItem) => {\n const existingIndex = tagsViewList.value.findIndex(\n item => item.path === tag.path\n )\n\n if (existingIndex === -1) {\n tagsViewList.value.push(tag)\n } else {\n const existing = tagsViewList.value[existingIndex]\n if (existing.title !== tag.title || !existing.originalTitle) {\n existing.title = tag.title\n existing.originalTitle = tag.originalTitle || existing.originalTitle\n }\n }\n\n setActiveTag(tag.path)\n syncPersist()\n }\n\n const removeTag = (index: number): string | null => {\n if (index >= 0 && index < tagsViewList.value.length) {\n const removed = tagsViewList.value.splice(index, 1)[0]?.path ?? null\n syncPersist()\n return removed\n }\n return null\n }\n\n const removeOtherTags = (index: number) => {\n if (index === 0) {\n tagsViewList.value = [tagsViewList.value[0]].filter(Boolean)\n } else {\n tagsViewList.value = [\n tagsViewList.value[0],\n tagsViewList.value[index],\n ].filter(Boolean)\n }\n syncPersist()\n }\n\n const removeLeftTags = (index: number) => {\n tagsViewList.value = [\n tagsViewList.value[0],\n ...tagsViewList.value.slice(index),\n ]\n syncPersist()\n }\n\n const removeRightTags = (index: number) => {\n tagsViewList.value = tagsViewList.value.slice(0, index + 1)\n syncPersist()\n }\n\n const removeAllTags = () => {\n tagsViewList.value = tagsViewList.value.filter(tag => tag.meta?.affix)\n syncPersist()\n }\n\n return {\n tagsViewList,\n activeTag,\n homePath,\n initTags,\n setActiveTag,\n addTag,\n removeTag,\n removeOtherTags,\n removeLeftTags,\n removeRightTags,\n removeAllTags,\n }\n}\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\n *\n * 内置功能:\n * - 路由变化自动添加标签\n * - 持久化(localStorage,可关闭)\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\n * - 水平滚轮滚动\n * - i18n 支持(labelFormatter)\n *\n * @example 基础用法\n * ```vue\n * <C_TagsView\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 自定义首页 + 菜单文案\n * ```vue\n * <C_TagsView\n * home-path=\"/dashboard\"\n * home-title=\"Dashboard\"\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"tags-view-container\">\n <div\n class=\"tags-track\"\n ref=\"tagsTrack\"\n @wheel=\"handleWheel\"\n >\n <div\n class=\"tags-container\"\n ref=\"tagsContainer\"\n >\n <NTag\n v-for=\"(tag, index) in tags.tagsViewList.value\"\n :key=\"tag.path\"\n :type=\"isActive(tag) ? 'primary' : 'default'\"\n :closable=\"!isAffix(tag)\"\n :data-path=\"tag.path\"\n @close.stop=\"handleClose(tag, index)\"\n @click=\"navigateToTag(tag)\"\n @contextmenu.prevent=\"\n (e: MouseEvent) => showContextMenu(e, tag, index)\n \"\n >\n <template #icon>\n <C_Icon\n :name=\"tag.icon\"\n :size=\"12\"\n />\n </template>\n {{ tag.title }}\n </NTag>\n </div>\n </div>\n <NDropdown\n v-if=\"contextMenuVisible\"\n :show=\"contextMenuVisible\"\n :options=\"contextMenuOptions\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n @clickoutside=\"closeContextMenu\"\n @select=\"handleContextMenuSelect\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, h } from 'vue'\n import { useRoute, useRouter } from 'vue-router'\n import { C_Icon } from '../C_Icon'\n import type { TagItem } from '../_shared'\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\n\n defineOptions({ name: 'C_TagsView' })\n\n export interface ContextMenuLabels {\n close?: string\n closeOthers?: string\n closeLeft?: string\n closeRight?: string\n closeAll?: string\n }\n\n const props = withDefaults(\n defineProps<{\n /**\n * 标签文本格式化函数(用于 i18n)\n */\n labelFormatter?: (label: string) => string\n /** 首页路径 */\n homePath?: string\n /** 首页标题(原始文本) */\n homeTitle?: string\n /** 首页图标 */\n homeIcon?: string\n /** 持久化 localStorage key,传空字符串禁用 */\n persistKey?: string\n /** 右键菜单文案(国际化适配) */\n contextMenuLabels?: ContextMenuLabels\n /** useTagsView 配置项(优先级最高) */\n tagsViewOptions?: UseTagsViewOptions\n }>(),\n {\n homePath: '/home',\n homeTitle: '首页',\n homeIcon: 'mdi:home',\n persistKey: '__tags_view_list__',\n contextMenuLabels: () => ({\n close: '关闭',\n closeOthers: '关闭其他',\n closeLeft: '关闭左侧',\n closeRight: '关闭右侧',\n closeAll: '关闭所有',\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 标签被关闭后跳转 */\n close: [fallbackPath: string]\n /** 关闭全部后 */\n closeAll: []\n }>()\n\n const route = useRoute()\n const router = useRouter()\n\n // ====== Tags composable ======\n const tags = useTagsView(\n props.tagsViewOptions ?? {\n persistKey: props.persistKey,\n homePath: props.homePath,\n }\n )\n\n // ====== 首次渲染前重新翻译持久化标签 ======\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\n const allRoutes = router.getRoutes()\n const translatedTags = tags.tagsViewList.value.map(tag => {\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\n const originalTitle =\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\n return {\n ...tag,\n originalTitle,\n title: props.labelFormatter!(originalTitle),\n }\n })\n tags.initTags(translatedTags)\n }\n\n const formatLabel = (title: string): string =>\n props.labelFormatter ? props.labelFormatter(title) : title\n\n // ====== UI State ======\n\n const contextMenuVisible = ref(false)\n const contextMenuX = ref(0)\n const contextMenuY = ref(0)\n const selectedTag = ref<TagItem | null>(null)\n const selectedIndex = ref(-1)\n const tagsTrack = ref<HTMLElement>()\n const tagsContainer = ref<HTMLElement>()\n\n // ====== Helpers ======\n const isActive = (tag: TagItem): boolean => tag.path === route.path\n const isAffix = (tag: TagItem) => tag.meta?.affix\n\n const handleWheel = (e: WheelEvent) => {\n const container = tagsContainer.value\n if (!container) return\n e.preventDefault()\n container.scrollTo({\n left: container.scrollLeft + e.deltaY,\n behavior: 'smooth',\n })\n }\n\n const scrollToTag = (path: string) => {\n nextTick(() => {\n const targetTag = tagsContainer.value?.querySelector(\n `[data-path=\"${path}\"]`\n ) as HTMLElement\n if (targetTag) {\n targetTag.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n })\n }\n })\n }\n\n // ====== Actions ======\n\n const navigateToTag = (tag: TagItem) => {\n if (tag.path !== route.path) {\n router.push(tag.path)\n }\n scrollToTag(tag.path)\n }\n\n const handleClose = (tag: TagItem, index: number) => {\n if (isAffix(tag)) return\n\n const wasActive = isActive(tag)\n const tagsBeforeRemove = tags.tagsViewList.value.length\n tags.removeTag(index)\n\n if (wasActive) {\n const remaining = tags.tagsViewList.value\n const wasLastTag = index === tagsBeforeRemove - 1\n let fallbackPath: string\n\n if (wasLastTag) {\n fallbackPath = remaining[index - 1]?.path || props.homePath\n } else {\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\n }\n\n router.push(fallbackPath)\n emit('close', fallbackPath)\n }\n }\n\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\n event.preventDefault()\n selectedTag.value = tag\n selectedIndex.value = index\n contextMenuVisible.value = true\n contextMenuX.value = event.clientX\n contextMenuY.value = event.clientY\n }\n\n const closeContextMenu = () => (contextMenuVisible.value = false)\n\n const contextMenuOptions = computed(() => {\n const labels = props.contextMenuLabels\n return [\n {\n type: 'option' as const,\n label: labels.close ?? '关闭',\n key: 'close',\n disabled: isAffix(selectedTag.value as TagItem),\n icon: () => h('span', { class: 'i-mdi:close' }),\n },\n {\n type: 'option' as const,\n label: labels.closeOthers ?? '关闭其他',\n key: 'closeOthers',\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\n },\n {\n type: 'option' as const,\n label: labels.closeLeft ?? '关闭左侧',\n key: 'closeLeft',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\n },\n {\n type: 'option' as const,\n label: labels.closeRight ?? '关闭右侧',\n key: 'closeRight',\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\n },\n {\n type: 'option' as const,\n label: labels.closeAll ?? '关闭所有',\n key: 'closeAll',\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\n },\n ]\n })\n\n const handleContextMenuSelect = (key: string) => {\n if (!selectedTag.value || selectedIndex.value === -1) return\n\n switch (key) {\n case 'close':\n handleClose(selectedTag.value, selectedIndex.value)\n break\n case 'closeOthers':\n tags.removeOtherTags(selectedIndex.value)\n break\n case 'closeLeft':\n tags.removeLeftTags(selectedIndex.value)\n break\n case 'closeRight':\n tags.removeRightTags(selectedIndex.value)\n break\n case 'closeAll':\n tags.removeAllTags()\n router.push(props.homePath)\n emit('closeAll')\n break\n }\n closeContextMenu()\n }\n\n // ====== 路由自动跟踪 ======\n watch(\n () => route.path,\n (newPath: string) => {\n const originalTitle =\n newPath === props.homePath\n ? props.homeTitle\n : (route.meta.title as string) || 'Unnamed Page'\n\n tags.addTag({\n path: newPath,\n originalTitle,\n title: formatLabel(originalTitle),\n icon:\n newPath === props.homePath\n ? props.homeIcon\n : (route.meta.icon as string),\n meta: { affix: route.meta.affix as boolean },\n })\n\n tags.setActiveTag(newPath)\n scrollToTag(newPath)\n },\n { immediate: true }\n )\n\n // ====== 暴露 ======\n defineExpose({\n /** useTagsView composable 实例 */\n tags,\n /** 滚动到指定标签 */\n scrollToTag,\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"C_TagsView2.js","names":[],"sources":["../src/components/C_TagsView/useTagsView.ts","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue","../src/components/C_TagsView/index.vue"],"sourcesContent":["import { ref, type Ref } from 'vue'\r\nimport type { TagItem } from '../_shared'\r\n\r\nexport interface UseTagsViewOptions {\r\n /** localStorage 持久化 key,传空字符串则不持久化 */\r\n persistKey?: string\r\n /** 首页路径,用于 removeAll 后的回退 */\r\n homePath?: string\r\n}\r\n\r\nconst STORAGE_KEY_DEFAULT = '__tags_view_list__'\r\n\r\n/**\r\n * 标签页管理 composable\r\n *\r\n * 独立于组件使用 — 可在任何地方管理标签状态\r\n *\r\n * @example 独立使用\r\n * ```ts\r\n * const tags = useTagsView({ persistKey: 'my-tags' })\r\n * tags.addTag({ path: '/home', title: '首页', meta: { affix: true } })\r\n * ```\r\n */\r\nexport function useTagsView(options: UseTagsViewOptions = {}) {\r\n const { persistKey = STORAGE_KEY_DEFAULT, homePath = '/home' } = options\r\n\r\n // ====== 持久化 ======\r\n const loadPersistedTags = (): TagItem[] => {\r\n if (!persistKey) return []\r\n try {\r\n const raw = localStorage.getItem(persistKey)\r\n return raw ? JSON.parse(raw) : []\r\n } catch {\r\n return []\r\n }\r\n }\r\n\r\n const persistTags = (tags: TagItem[]) => {\r\n if (!persistKey) return\r\n try {\r\n localStorage.setItem(persistKey, JSON.stringify(tags))\r\n } catch {\r\n /* silently fail */\r\n }\r\n }\r\n\r\n // ====== State ======\r\n const tagsViewList: Ref<TagItem[]> = ref(loadPersistedTags())\r\n const activeTag = ref('')\r\n\r\n const syncPersist = () => persistTags(tagsViewList.value)\r\n\r\n // ====== Actions ======\r\n\r\n const initTags = (tags?: TagItem[]) => {\r\n if (tags) {\r\n tagsViewList.value = tags\r\n } else {\r\n // 去重\r\n tagsViewList.value = [\r\n ...new Map(tagsViewList.value.map(tag => [tag.path, tag])).values(),\r\n ]\r\n }\r\n syncPersist()\r\n }\r\n\r\n const setActiveTag = (path: string) => {\r\n activeTag.value = path\r\n }\r\n\r\n const addTag = (tag: TagItem) => {\r\n const existingIndex = tagsViewList.value.findIndex(\r\n item => item.path === tag.path\r\n )\r\n\r\n if (existingIndex === -1) {\r\n tagsViewList.value.push(tag)\r\n } else {\r\n const existing = tagsViewList.value[existingIndex]\r\n if (existing.title !== tag.title || !existing.originalTitle) {\r\n existing.title = tag.title\r\n existing.originalTitle = tag.originalTitle || existing.originalTitle\r\n }\r\n }\r\n\r\n setActiveTag(tag.path)\r\n syncPersist()\r\n }\r\n\r\n const removeTag = (index: number): string | null => {\r\n if (index >= 0 && index < tagsViewList.value.length) {\r\n const removed = tagsViewList.value.splice(index, 1)[0]?.path ?? null\r\n syncPersist()\r\n return removed\r\n }\r\n return null\r\n }\r\n\r\n const removeOtherTags = (index: number) => {\r\n if (index === 0) {\r\n tagsViewList.value = [tagsViewList.value[0]].filter(Boolean)\r\n } else {\r\n tagsViewList.value = [\r\n tagsViewList.value[0],\r\n tagsViewList.value[index],\r\n ].filter(Boolean)\r\n }\r\n syncPersist()\r\n }\r\n\r\n const removeLeftTags = (index: number) => {\r\n tagsViewList.value = [\r\n tagsViewList.value[0],\r\n ...tagsViewList.value.slice(index),\r\n ]\r\n syncPersist()\r\n }\r\n\r\n const removeRightTags = (index: number) => {\r\n tagsViewList.value = tagsViewList.value.slice(0, index + 1)\r\n syncPersist()\r\n }\r\n\r\n const removeAllTags = () => {\r\n tagsViewList.value = tagsViewList.value.filter(tag => tag.meta?.affix)\r\n syncPersist()\r\n }\r\n\r\n return {\r\n tagsViewList,\r\n activeTag,\r\n homePath,\r\n initTags,\r\n setActiveTag,\r\n addTag,\r\n removeTag,\r\n removeOtherTags,\r\n removeLeftTags,\r\n removeRightTags,\r\n removeAllTags,\r\n }\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 通用标签页导航组件 — 路由感知的多标签管理\r\n *\r\n * 内置功能:\r\n * - 路由变化自动添加标签\r\n * - 持久化(localStorage,可关闭)\r\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\r\n * - 水平滚轮滚动\r\n * - i18n 支持(labelFormatter)\r\n *\r\n * @example 基础用法\r\n * ```vue\r\n * <C_TagsView\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 自定义首页 + 菜单文案\r\n * ```vue\r\n * <C_TagsView\r\n * home-path=\"/dashboard\"\r\n * home-title=\"Dashboard\"\r\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"tags-view-container\">\r\n <div\r\n class=\"tags-track\"\r\n ref=\"tagsTrack\"\r\n @wheel=\"handleWheel\"\r\n >\r\n <div\r\n class=\"tags-container\"\r\n ref=\"tagsContainer\"\r\n >\r\n <NTag\r\n v-for=\"(tag, index) in tags.tagsViewList.value\"\r\n :key=\"tag.path\"\r\n :type=\"isActive(tag) ? 'primary' : 'default'\"\r\n :closable=\"!isAffix(tag)\"\r\n :data-path=\"tag.path\"\r\n @close.stop=\"handleClose(tag, index)\"\r\n @click=\"navigateToTag(tag)\"\r\n @contextmenu.prevent=\"\r\n (e: MouseEvent) => showContextMenu(e, tag, index)\r\n \"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"tag.icon\"\r\n :size=\"12\"\r\n />\r\n </template>\r\n {{ tag.title }}\r\n </NTag>\r\n </div>\r\n </div>\r\n <NDropdown\r\n v-if=\"contextMenuVisible\"\r\n :show=\"contextMenuVisible\"\r\n :options=\"contextMenuOptions\"\r\n :x=\"contextMenuX\"\r\n :y=\"contextMenuY\"\r\n @clickoutside=\"closeContextMenu\"\r\n @select=\"handleContextMenuSelect\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, h } from 'vue'\r\n import { useRoute, useRouter } from 'vue-router'\r\n import { C_Icon } from '../C_Icon'\r\n import type { TagItem } from '../_shared'\r\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\r\n\r\n defineOptions({ name: 'C_TagsView' })\r\n\r\n export interface ContextMenuLabels {\r\n close?: string\r\n closeOthers?: string\r\n closeLeft?: string\r\n closeRight?: string\r\n closeAll?: string\r\n }\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 标签文本格式化函数(用于 i18n)\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 首页路径 */\r\n homePath?: string\r\n /** 首页标题(原始文本) */\r\n homeTitle?: string\r\n /** 首页图标 */\r\n homeIcon?: string\r\n /** 持久化 localStorage key,传空字符串禁用 */\r\n persistKey?: string\r\n /** 右键菜单文案(国际化适配) */\r\n contextMenuLabels?: ContextMenuLabels\r\n /** useTagsView 配置项(优先级最高) */\r\n tagsViewOptions?: UseTagsViewOptions\r\n }>(),\r\n {\r\n homePath: '/home',\r\n homeTitle: '首页',\r\n homeIcon: 'mdi:home',\r\n persistKey: '__tags_view_list__',\r\n contextMenuLabels: () => ({\r\n close: '关闭',\r\n closeOthers: '关闭其他',\r\n closeLeft: '关闭左侧',\r\n closeRight: '关闭右侧',\r\n closeAll: '关闭所有',\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 标签被关闭后跳转 */\r\n close: [fallbackPath: string]\r\n /** 关闭全部后 */\r\n closeAll: []\r\n }>()\r\n\r\n const route = useRoute()\r\n const router = useRouter()\r\n\r\n // ====== Tags composable ======\r\n const tags = useTagsView(\r\n props.tagsViewOptions ?? {\r\n persistKey: props.persistKey,\r\n homePath: props.homePath,\r\n }\r\n )\r\n\r\n // ====== 首次渲染前重新翻译持久化标签 ======\r\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\r\n const allRoutes = router.getRoutes()\r\n const translatedTags = tags.tagsViewList.value.map(tag => {\r\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\r\n const originalTitle =\r\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\r\n return {\r\n ...tag,\r\n originalTitle,\r\n title: props.labelFormatter!(originalTitle),\r\n }\r\n })\r\n tags.initTags(translatedTags)\r\n }\r\n\r\n const formatLabel = (title: string): string =>\r\n props.labelFormatter ? props.labelFormatter(title) : title\r\n\r\n // ====== UI State ======\r\n\r\n const contextMenuVisible = ref(false)\r\n const contextMenuX = ref(0)\r\n const contextMenuY = ref(0)\r\n const selectedTag = ref<TagItem | null>(null)\r\n const selectedIndex = ref(-1)\r\n const tagsTrack = ref<HTMLElement>()\r\n const tagsContainer = ref<HTMLElement>()\r\n\r\n // ====== Helpers ======\r\n const isActive = (tag: TagItem): boolean => tag.path === route.path\r\n const isAffix = (tag: TagItem) => tag.meta?.affix\r\n\r\n const handleWheel = (e: WheelEvent) => {\r\n const container = tagsContainer.value\r\n if (!container) return\r\n e.preventDefault()\r\n container.scrollTo({\r\n left: container.scrollLeft + e.deltaY,\r\n behavior: 'smooth',\r\n })\r\n }\r\n\r\n const scrollToTag = (path: string) => {\r\n nextTick(() => {\r\n const targetTag = tagsContainer.value?.querySelector(\r\n `[data-path=\"${path}\"]`\r\n ) as HTMLElement\r\n if (targetTag) {\r\n targetTag.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'nearest',\r\n inline: 'center',\r\n })\r\n }\r\n })\r\n }\r\n\r\n // ====== Actions ======\r\n\r\n const navigateToTag = (tag: TagItem) => {\r\n if (tag.path !== route.path) {\r\n router.push(tag.path)\r\n }\r\n scrollToTag(tag.path)\r\n }\r\n\r\n const handleClose = (tag: TagItem, index: number) => {\r\n if (isAffix(tag)) return\r\n\r\n const wasActive = isActive(tag)\r\n const tagsBeforeRemove = tags.tagsViewList.value.length\r\n tags.removeTag(index)\r\n\r\n if (wasActive) {\r\n const remaining = tags.tagsViewList.value\r\n const wasLastTag = index === tagsBeforeRemove - 1\r\n let fallbackPath: string\r\n\r\n if (wasLastTag) {\r\n fallbackPath = remaining[index - 1]?.path || props.homePath\r\n } else {\r\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\r\n }\r\n\r\n router.push(fallbackPath)\r\n emit('close', fallbackPath)\r\n }\r\n }\r\n\r\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\r\n event.preventDefault()\r\n selectedTag.value = tag\r\n selectedIndex.value = index\r\n contextMenuVisible.value = true\r\n contextMenuX.value = event.clientX\r\n contextMenuY.value = event.clientY\r\n }\r\n\r\n const closeContextMenu = () => (contextMenuVisible.value = false)\r\n\r\n const contextMenuOptions = computed(() => {\r\n const labels = props.contextMenuLabels\r\n return [\r\n {\r\n type: 'option' as const,\r\n label: labels.close ?? '关闭',\r\n key: 'close',\r\n disabled: isAffix(selectedTag.value as TagItem),\r\n icon: () => h('span', { class: 'i-mdi:close' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeOthers ?? '关闭其他',\r\n key: 'closeOthers',\r\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeLeft ?? '关闭左侧',\r\n key: 'closeLeft',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeRight ?? '关闭右侧',\r\n key: 'closeRight',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeAll ?? '关闭所有',\r\n key: 'closeAll',\r\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\r\n },\r\n ]\r\n })\r\n\r\n const handleContextMenuSelect = (key: string) => {\r\n if (!selectedTag.value || selectedIndex.value === -1) return\r\n\r\n switch (key) {\r\n case 'close':\r\n handleClose(selectedTag.value, selectedIndex.value)\r\n break\r\n case 'closeOthers':\r\n tags.removeOtherTags(selectedIndex.value)\r\n break\r\n case 'closeLeft':\r\n tags.removeLeftTags(selectedIndex.value)\r\n break\r\n case 'closeRight':\r\n tags.removeRightTags(selectedIndex.value)\r\n break\r\n case 'closeAll':\r\n tags.removeAllTags()\r\n router.push(props.homePath)\r\n emit('closeAll')\r\n break\r\n }\r\n closeContextMenu()\r\n }\r\n\r\n // ====== 路由自动跟踪 ======\r\n watch(\r\n () => route.path,\r\n (newPath: string) => {\r\n const originalTitle =\r\n newPath === props.homePath\r\n ? props.homeTitle\r\n : (route.meta.title as string) || 'Unnamed Page'\r\n\r\n tags.addTag({\r\n path: newPath,\r\n originalTitle,\r\n title: formatLabel(originalTitle),\r\n icon:\r\n newPath === props.homePath\r\n ? props.homeIcon\r\n : (route.meta.icon as string),\r\n meta: { affix: route.meta.affix as boolean },\r\n })\r\n\r\n tags.setActiveTag(newPath)\r\n scrollToTag(newPath)\r\n },\r\n { immediate: true }\r\n )\r\n\r\n // ====== 暴露 ======\r\n defineExpose({\r\n /** useTagsView composable 实例 */\r\n tags,\r\n /** 滚动到指定标签 */\r\n scrollToTag,\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 * @Description: 通用标签页导航组件 — 路由感知的多标签管理\r\n *\r\n * 内置功能:\r\n * - 路由变化自动添加标签\r\n * - 持久化(localStorage,可关闭)\r\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\r\n * - 水平滚轮滚动\r\n * - i18n 支持(labelFormatter)\r\n *\r\n * @example 基础用法\r\n * ```vue\r\n * <C_TagsView\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 自定义首页 + 菜单文案\r\n * ```vue\r\n * <C_TagsView\r\n * home-path=\"/dashboard\"\r\n * home-title=\"Dashboard\"\r\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"tags-view-container\">\r\n <div\r\n class=\"tags-track\"\r\n ref=\"tagsTrack\"\r\n @wheel=\"handleWheel\"\r\n >\r\n <div\r\n class=\"tags-container\"\r\n ref=\"tagsContainer\"\r\n >\r\n <NTag\r\n v-for=\"(tag, index) in tags.tagsViewList.value\"\r\n :key=\"tag.path\"\r\n :type=\"isActive(tag) ? 'primary' : 'default'\"\r\n :closable=\"!isAffix(tag)\"\r\n :data-path=\"tag.path\"\r\n @close.stop=\"handleClose(tag, index)\"\r\n @click=\"navigateToTag(tag)\"\r\n @contextmenu.prevent=\"\r\n (e: MouseEvent) => showContextMenu(e, tag, index)\r\n \"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"tag.icon\"\r\n :size=\"12\"\r\n />\r\n </template>\r\n {{ tag.title }}\r\n </NTag>\r\n </div>\r\n </div>\r\n <NDropdown\r\n v-if=\"contextMenuVisible\"\r\n :show=\"contextMenuVisible\"\r\n :options=\"contextMenuOptions\"\r\n :x=\"contextMenuX\"\r\n :y=\"contextMenuY\"\r\n @clickoutside=\"closeContextMenu\"\r\n @select=\"handleContextMenuSelect\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, h } from 'vue'\r\n import { useRoute, useRouter } from 'vue-router'\r\n import { C_Icon } from '../C_Icon'\r\n import type { TagItem } from '../_shared'\r\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\r\n\r\n defineOptions({ name: 'C_TagsView' })\r\n\r\n export interface ContextMenuLabels {\r\n close?: string\r\n closeOthers?: string\r\n closeLeft?: string\r\n closeRight?: string\r\n closeAll?: string\r\n }\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 标签文本格式化函数(用于 i18n)\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 首页路径 */\r\n homePath?: string\r\n /** 首页标题(原始文本) */\r\n homeTitle?: string\r\n /** 首页图标 */\r\n homeIcon?: string\r\n /** 持久化 localStorage key,传空字符串禁用 */\r\n persistKey?: string\r\n /** 右键菜单文案(国际化适配) */\r\n contextMenuLabels?: ContextMenuLabels\r\n /** useTagsView 配置项(优先级最高) */\r\n tagsViewOptions?: UseTagsViewOptions\r\n }>(),\r\n {\r\n homePath: '/home',\r\n homeTitle: '首页',\r\n homeIcon: 'mdi:home',\r\n persistKey: '__tags_view_list__',\r\n contextMenuLabels: () => ({\r\n close: '关闭',\r\n closeOthers: '关闭其他',\r\n closeLeft: '关闭左侧',\r\n closeRight: '关闭右侧',\r\n closeAll: '关闭所有',\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 标签被关闭后跳转 */\r\n close: [fallbackPath: string]\r\n /** 关闭全部后 */\r\n closeAll: []\r\n }>()\r\n\r\n const route = useRoute()\r\n const router = useRouter()\r\n\r\n // ====== Tags composable ======\r\n const tags = useTagsView(\r\n props.tagsViewOptions ?? {\r\n persistKey: props.persistKey,\r\n homePath: props.homePath,\r\n }\r\n )\r\n\r\n // ====== 首次渲染前重新翻译持久化标签 ======\r\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\r\n const allRoutes = router.getRoutes()\r\n const translatedTags = tags.tagsViewList.value.map(tag => {\r\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\r\n const originalTitle =\r\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\r\n return {\r\n ...tag,\r\n originalTitle,\r\n title: props.labelFormatter!(originalTitle),\r\n }\r\n })\r\n tags.initTags(translatedTags)\r\n }\r\n\r\n const formatLabel = (title: string): string =>\r\n props.labelFormatter ? props.labelFormatter(title) : title\r\n\r\n // ====== UI State ======\r\n\r\n const contextMenuVisible = ref(false)\r\n const contextMenuX = ref(0)\r\n const contextMenuY = ref(0)\r\n const selectedTag = ref<TagItem | null>(null)\r\n const selectedIndex = ref(-1)\r\n const tagsTrack = ref<HTMLElement>()\r\n const tagsContainer = ref<HTMLElement>()\r\n\r\n // ====== Helpers ======\r\n const isActive = (tag: TagItem): boolean => tag.path === route.path\r\n const isAffix = (tag: TagItem) => tag.meta?.affix\r\n\r\n const handleWheel = (e: WheelEvent) => {\r\n const container = tagsContainer.value\r\n if (!container) return\r\n e.preventDefault()\r\n container.scrollTo({\r\n left: container.scrollLeft + e.deltaY,\r\n behavior: 'smooth',\r\n })\r\n }\r\n\r\n const scrollToTag = (path: string) => {\r\n nextTick(() => {\r\n const targetTag = tagsContainer.value?.querySelector(\r\n `[data-path=\"${path}\"]`\r\n ) as HTMLElement\r\n if (targetTag) {\r\n targetTag.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'nearest',\r\n inline: 'center',\r\n })\r\n }\r\n })\r\n }\r\n\r\n // ====== Actions ======\r\n\r\n const navigateToTag = (tag: TagItem) => {\r\n if (tag.path !== route.path) {\r\n router.push(tag.path)\r\n }\r\n scrollToTag(tag.path)\r\n }\r\n\r\n const handleClose = (tag: TagItem, index: number) => {\r\n if (isAffix(tag)) return\r\n\r\n const wasActive = isActive(tag)\r\n const tagsBeforeRemove = tags.tagsViewList.value.length\r\n tags.removeTag(index)\r\n\r\n if (wasActive) {\r\n const remaining = tags.tagsViewList.value\r\n const wasLastTag = index === tagsBeforeRemove - 1\r\n let fallbackPath: string\r\n\r\n if (wasLastTag) {\r\n fallbackPath = remaining[index - 1]?.path || props.homePath\r\n } else {\r\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\r\n }\r\n\r\n router.push(fallbackPath)\r\n emit('close', fallbackPath)\r\n }\r\n }\r\n\r\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\r\n event.preventDefault()\r\n selectedTag.value = tag\r\n selectedIndex.value = index\r\n contextMenuVisible.value = true\r\n contextMenuX.value = event.clientX\r\n contextMenuY.value = event.clientY\r\n }\r\n\r\n const closeContextMenu = () => (contextMenuVisible.value = false)\r\n\r\n const contextMenuOptions = computed(() => {\r\n const labels = props.contextMenuLabels\r\n return [\r\n {\r\n type: 'option' as const,\r\n label: labels.close ?? '关闭',\r\n key: 'close',\r\n disabled: isAffix(selectedTag.value as TagItem),\r\n icon: () => h('span', { class: 'i-mdi:close' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeOthers ?? '关闭其他',\r\n key: 'closeOthers',\r\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeLeft ?? '关闭左侧',\r\n key: 'closeLeft',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeRight ?? '关闭右侧',\r\n key: 'closeRight',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeAll ?? '关闭所有',\r\n key: 'closeAll',\r\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\r\n },\r\n ]\r\n })\r\n\r\n const handleContextMenuSelect = (key: string) => {\r\n if (!selectedTag.value || selectedIndex.value === -1) return\r\n\r\n switch (key) {\r\n case 'close':\r\n handleClose(selectedTag.value, selectedIndex.value)\r\n break\r\n case 'closeOthers':\r\n tags.removeOtherTags(selectedIndex.value)\r\n break\r\n case 'closeLeft':\r\n tags.removeLeftTags(selectedIndex.value)\r\n break\r\n case 'closeRight':\r\n tags.removeRightTags(selectedIndex.value)\r\n break\r\n case 'closeAll':\r\n tags.removeAllTags()\r\n router.push(props.homePath)\r\n emit('closeAll')\r\n break\r\n }\r\n closeContextMenu()\r\n }\r\n\r\n // ====== 路由自动跟踪 ======\r\n watch(\r\n () => route.path,\r\n (newPath: string) => {\r\n const originalTitle =\r\n newPath === props.homePath\r\n ? props.homeTitle\r\n : (route.meta.title as string) || 'Unnamed Page'\r\n\r\n tags.addTag({\r\n path: newPath,\r\n originalTitle,\r\n title: formatLabel(originalTitle),\r\n icon:\r\n newPath === props.homePath\r\n ? props.homeIcon\r\n : (route.meta.icon as string),\r\n meta: { affix: route.meta.affix as boolean },\r\n })\r\n\r\n tags.setActiveTag(newPath)\r\n scrollToTag(newPath)\r\n },\r\n { immediate: true }\r\n )\r\n\r\n // ====== 暴露 ======\r\n defineExpose({\r\n /** useTagsView composable 实例 */\r\n tags,\r\n /** 滚动到指定标签 */\r\n scrollToTag,\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 * @Description: 通用标签页导航组件 — 路由感知的多标签管理\r\n *\r\n * 内置功能:\r\n * - 路由变化自动添加标签\r\n * - 持久化(localStorage,可关闭)\r\n * - 右键菜单(关闭/关闭其他/关闭左侧/关闭右侧/关闭所有)\r\n * - 水平滚轮滚动\r\n * - i18n 支持(labelFormatter)\r\n *\r\n * @example 基础用法\r\n * ```vue\r\n * <C_TagsView\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 自定义首页 + 菜单文案\r\n * ```vue\r\n * <C_TagsView\r\n * home-path=\"/dashboard\"\r\n * home-title=\"Dashboard\"\r\n * :context-menu-labels=\"{ close: 'Close', closeAll: 'Close All', ... }\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"tags-view-container\">\r\n <div\r\n class=\"tags-track\"\r\n ref=\"tagsTrack\"\r\n @wheel=\"handleWheel\"\r\n >\r\n <div\r\n class=\"tags-container\"\r\n ref=\"tagsContainer\"\r\n >\r\n <NTag\r\n v-for=\"(tag, index) in tags.tagsViewList.value\"\r\n :key=\"tag.path\"\r\n :type=\"isActive(tag) ? 'primary' : 'default'\"\r\n :closable=\"!isAffix(tag)\"\r\n :data-path=\"tag.path\"\r\n @close.stop=\"handleClose(tag, index)\"\r\n @click=\"navigateToTag(tag)\"\r\n @contextmenu.prevent=\"\r\n (e: MouseEvent) => showContextMenu(e, tag, index)\r\n \"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"tag.icon\"\r\n :size=\"12\"\r\n />\r\n </template>\r\n {{ tag.title }}\r\n </NTag>\r\n </div>\r\n </div>\r\n <NDropdown\r\n v-if=\"contextMenuVisible\"\r\n :show=\"contextMenuVisible\"\r\n :options=\"contextMenuOptions\"\r\n :x=\"contextMenuX\"\r\n :y=\"contextMenuY\"\r\n @clickoutside=\"closeContextMenu\"\r\n @select=\"handleContextMenuSelect\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, h } from 'vue'\r\n import { useRoute, useRouter } from 'vue-router'\r\n import { C_Icon } from '../C_Icon'\r\n import type { TagItem } from '../_shared'\r\n import { useTagsView, type UseTagsViewOptions } from './useTagsView'\r\n\r\n defineOptions({ name: 'C_TagsView' })\r\n\r\n export interface ContextMenuLabels {\r\n close?: string\r\n closeOthers?: string\r\n closeLeft?: string\r\n closeRight?: string\r\n closeAll?: string\r\n }\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 标签文本格式化函数(用于 i18n)\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 首页路径 */\r\n homePath?: string\r\n /** 首页标题(原始文本) */\r\n homeTitle?: string\r\n /** 首页图标 */\r\n homeIcon?: string\r\n /** 持久化 localStorage key,传空字符串禁用 */\r\n persistKey?: string\r\n /** 右键菜单文案(国际化适配) */\r\n contextMenuLabels?: ContextMenuLabels\r\n /** useTagsView 配置项(优先级最高) */\r\n tagsViewOptions?: UseTagsViewOptions\r\n }>(),\r\n {\r\n homePath: '/home',\r\n homeTitle: '首页',\r\n homeIcon: 'mdi:home',\r\n persistKey: '__tags_view_list__',\r\n contextMenuLabels: () => ({\r\n close: '关闭',\r\n closeOthers: '关闭其他',\r\n closeLeft: '关闭左侧',\r\n closeRight: '关闭右侧',\r\n closeAll: '关闭所有',\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 标签被关闭后跳转 */\r\n close: [fallbackPath: string]\r\n /** 关闭全部后 */\r\n closeAll: []\r\n }>()\r\n\r\n const route = useRoute()\r\n const router = useRouter()\r\n\r\n // ====== Tags composable ======\r\n const tags = useTagsView(\r\n props.tagsViewOptions ?? {\r\n persistKey: props.persistKey,\r\n homePath: props.homePath,\r\n }\r\n )\r\n\r\n // ====== 首次渲染前重新翻译持久化标签 ======\r\n if (tags.tagsViewList.value.length > 0 && props.labelFormatter) {\r\n const allRoutes = router.getRoutes()\r\n const translatedTags = tags.tagsViewList.value.map(tag => {\r\n const matchedRoute = allRoutes.find(r => r.path === tag.path)\r\n const originalTitle =\r\n tag.originalTitle || (matchedRoute?.meta?.title as string) || tag.title\r\n return {\r\n ...tag,\r\n originalTitle,\r\n title: props.labelFormatter!(originalTitle),\r\n }\r\n })\r\n tags.initTags(translatedTags)\r\n }\r\n\r\n const formatLabel = (title: string): string =>\r\n props.labelFormatter ? props.labelFormatter(title) : title\r\n\r\n // ====== UI State ======\r\n\r\n const contextMenuVisible = ref(false)\r\n const contextMenuX = ref(0)\r\n const contextMenuY = ref(0)\r\n const selectedTag = ref<TagItem | null>(null)\r\n const selectedIndex = ref(-1)\r\n const tagsTrack = ref<HTMLElement>()\r\n const tagsContainer = ref<HTMLElement>()\r\n\r\n // ====== Helpers ======\r\n const isActive = (tag: TagItem): boolean => tag.path === route.path\r\n const isAffix = (tag: TagItem) => tag.meta?.affix\r\n\r\n const handleWheel = (e: WheelEvent) => {\r\n const container = tagsContainer.value\r\n if (!container) return\r\n e.preventDefault()\r\n container.scrollTo({\r\n left: container.scrollLeft + e.deltaY,\r\n behavior: 'smooth',\r\n })\r\n }\r\n\r\n const scrollToTag = (path: string) => {\r\n nextTick(() => {\r\n const targetTag = tagsContainer.value?.querySelector(\r\n `[data-path=\"${path}\"]`\r\n ) as HTMLElement\r\n if (targetTag) {\r\n targetTag.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'nearest',\r\n inline: 'center',\r\n })\r\n }\r\n })\r\n }\r\n\r\n // ====== Actions ======\r\n\r\n const navigateToTag = (tag: TagItem) => {\r\n if (tag.path !== route.path) {\r\n router.push(tag.path)\r\n }\r\n scrollToTag(tag.path)\r\n }\r\n\r\n const handleClose = (tag: TagItem, index: number) => {\r\n if (isAffix(tag)) return\r\n\r\n const wasActive = isActive(tag)\r\n const tagsBeforeRemove = tags.tagsViewList.value.length\r\n tags.removeTag(index)\r\n\r\n if (wasActive) {\r\n const remaining = tags.tagsViewList.value\r\n const wasLastTag = index === tagsBeforeRemove - 1\r\n let fallbackPath: string\r\n\r\n if (wasLastTag) {\r\n fallbackPath = remaining[index - 1]?.path || props.homePath\r\n } else {\r\n fallbackPath = remaining[remaining.length - 1]?.path || props.homePath\r\n }\r\n\r\n router.push(fallbackPath)\r\n emit('close', fallbackPath)\r\n }\r\n }\r\n\r\n const showContextMenu = (event: MouseEvent, tag: TagItem, index: number) => {\r\n event.preventDefault()\r\n selectedTag.value = tag\r\n selectedIndex.value = index\r\n contextMenuVisible.value = true\r\n contextMenuX.value = event.clientX\r\n contextMenuY.value = event.clientY\r\n }\r\n\r\n const closeContextMenu = () => (contextMenuVisible.value = false)\r\n\r\n const contextMenuOptions = computed(() => {\r\n const labels = props.contextMenuLabels\r\n return [\r\n {\r\n type: 'option' as const,\r\n label: labels.close ?? '关闭',\r\n key: 'close',\r\n disabled: isAffix(selectedTag.value as TagItem),\r\n icon: () => h('span', { class: 'i-mdi:close' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeOthers ?? '关闭其他',\r\n key: 'closeOthers',\r\n icon: () => h('span', { class: 'i-mdi:arrow-left-right-bold' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeLeft ?? '关闭左侧',\r\n key: 'closeLeft',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-left' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeRight ?? '关闭右侧',\r\n key: 'closeRight',\r\n icon: () => h('span', { class: 'i-mdi:align-horizontal-right' }),\r\n },\r\n {\r\n type: 'option' as const,\r\n label: labels.closeAll ?? '关闭所有',\r\n key: 'closeAll',\r\n icon: () => h('span', { class: 'i-mdi:tally-mark-5' }),\r\n },\r\n ]\r\n })\r\n\r\n const handleContextMenuSelect = (key: string) => {\r\n if (!selectedTag.value || selectedIndex.value === -1) return\r\n\r\n switch (key) {\r\n case 'close':\r\n handleClose(selectedTag.value, selectedIndex.value)\r\n break\r\n case 'closeOthers':\r\n tags.removeOtherTags(selectedIndex.value)\r\n break\r\n case 'closeLeft':\r\n tags.removeLeftTags(selectedIndex.value)\r\n break\r\n case 'closeRight':\r\n tags.removeRightTags(selectedIndex.value)\r\n break\r\n case 'closeAll':\r\n tags.removeAllTags()\r\n router.push(props.homePath)\r\n emit('closeAll')\r\n break\r\n }\r\n closeContextMenu()\r\n }\r\n\r\n // ====== 路由自动跟踪 ======\r\n watch(\r\n () => route.path,\r\n (newPath: string) => {\r\n const originalTitle =\r\n newPath === props.homePath\r\n ? props.homeTitle\r\n : (route.meta.title as string) || 'Unnamed Page'\r\n\r\n tags.addTag({\r\n path: newPath,\r\n originalTitle,\r\n title: formatLabel(originalTitle),\r\n icon:\r\n newPath === props.homePath\r\n ? props.homeIcon\r\n : (route.meta.icon as string),\r\n meta: { affix: route.meta.affix as boolean },\r\n })\r\n\r\n tags.setActiveTag(newPath)\r\n scrollToTag(newPath)\r\n },\r\n { immediate: true }\r\n )\r\n\r\n // ====== 暴露 ======\r\n defineExpose({\r\n /** useTagsView composable 实例 */\r\n tags,\r\n /** 滚动到指定标签 */\r\n scrollToTag,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
@@ -110,17 +110,17 @@ declare const __VLS_export: vue.DefineComponent<CronProps, {
110
110
  reset: typeof handleReset;
111
111
  validate: () => CronValidation;
112
112
  }, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
113
- "update:modelValue": (value: string) => any;
114
113
  change: (value: string) => any;
114
+ "update:modelValue": (value: string) => any;
115
115
  "validation-change": (result: CronValidation) => any;
116
116
  }, string, vue.PublicProps, Readonly<CronProps> & Readonly<{
117
- "onUpdate:modelValue"?: ((value: string) => any) | undefined;
118
117
  onChange?: ((value: string) => any) | undefined;
118
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
119
119
  "onValidation-change"?: ((result: CronValidation) => any) | undefined;
120
120
  }>, {
121
121
  height: string | number;
122
- modelValue: string;
123
122
  disabled: boolean;
123
+ modelValue: string;
124
124
  showPreview: boolean;
125
125
  previewCount: number;
126
126
  showTemplates: boolean;
@@ -112,22 +112,22 @@ interface FormulaEditorExpose {
112
112
  //#endregion
113
113
  //#region src/components/C_FormulaEditor/index.vue.d.ts
114
114
  declare const __VLS_export: vue.DefineComponent<FormulaEditorProps, FormulaEditorExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
115
- "update:modelValue": (value: string) => any;
116
115
  change: (value: string) => any;
116
+ "update:modelValue": (value: string) => any;
117
117
  "validation-change": (result: FormulaValidation) => any;
118
118
  }, string, vue.PublicProps, Readonly<FormulaEditorProps> & Readonly<{
119
- "onUpdate:modelValue"?: ((value: string) => any) | undefined;
120
119
  onChange?: ((value: string) => any) | undefined;
120
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
121
121
  "onValidation-change"?: ((result: FormulaValidation) => any) | undefined;
122
122
  }>, {
123
123
  height: string | number;
124
- modelValue: string;
125
- placeholder: string;
126
124
  disabled: boolean;
127
- showPreview: boolean;
125
+ placeholder: string;
126
+ modelValue: string;
128
127
  variables: FormulaVariable[];
129
128
  functions: FormulaFunction[];
130
129
  sampleData: Record<string, number | string | boolean>;
130
+ showPreview: boolean;
131
131
  showKeyboard: boolean;
132
132
  showVariablePanel: boolean;
133
133
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
@@ -151,8 +151,8 @@ interface NotificationCenterExpose {
151
151
  //#region src/components/C_NotificationCenter/index.vue.d.ts
152
152
  declare const __VLS_export: vue.DefineComponent<NotificationCenterProps, NotificationCenterExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
153
153
  delete: (ids: string[]) => any;
154
- read: (ids: string[]) => any;
155
154
  itemClick: (message: NotificationMessage) => any;
155
+ read: (ids: string[]) => any;
156
156
  allRead: (category?: NotificationCategory | undefined) => any;
157
157
  unreadChange: (count: number) => any;
158
158
  wsStatusChange: (status: string) => any;
@@ -160,8 +160,8 @@ declare const __VLS_export: vue.DefineComponent<NotificationCenterProps, Notific
160
160
  navigate: (url: string) => any;
161
161
  }, string, vue.PublicProps, Readonly<NotificationCenterProps> & Readonly<{
162
162
  onDelete?: ((ids: string[]) => any) | undefined;
163
- onRead?: ((ids: string[]) => any) | undefined;
164
163
  onItemClick?: ((message: NotificationMessage) => any) | undefined;
164
+ onRead?: ((ids: string[]) => any) | undefined;
165
165
  onAllRead?: ((category?: NotificationCategory | undefined) => any) | undefined;
166
166
  onUnreadChange?: ((count: number) => any) | undefined;
167
167
  onWsStatusChange?: ((status: string) => any) | undefined;
@@ -196,27 +196,27 @@ type __VLS_Slots = {} & {
196
196
  area?: (props: typeof __VLS_11) => any;
197
197
  };
198
198
  declare const __VLS_base: vue.DefineComponent<UploadProps, UploadExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
199
- change: (fileList: UploadFileItem[]) => any;
200
- success: (file: UploadFileItem, response: any) => any;
201
199
  error: (file: UploadFileItem, error: Error) => any;
200
+ success: (file: UploadFileItem, response: any) => any;
201
+ change: (fileList: UploadFileItem[]) => any;
202
202
  progress: (file: UploadFileItem, percent: number) => any;
203
203
  remove: (file: UploadFileItem) => any;
204
204
  finish: (fileList: UploadFileItem[]) => any;
205
205
  exceed: (files: File[], fileList: UploadFileItem[]) => any;
206
206
  }, string, vue.PublicProps, Readonly<UploadProps> & Readonly<{
207
- onChange?: ((fileList: UploadFileItem[]) => any) | undefined;
208
- onSuccess?: ((file: UploadFileItem, response: any) => any) | undefined;
209
207
  onError?: ((file: UploadFileItem, error: Error) => any) | undefined;
208
+ onSuccess?: ((file: UploadFileItem, response: any) => any) | undefined;
209
+ onChange?: ((fileList: UploadFileItem[]) => any) | undefined;
210
210
  onProgress?: ((file: UploadFileItem, percent: number) => any) | undefined;
211
211
  onRemove?: ((file: UploadFileItem) => any) | undefined;
212
212
  onFinish?: ((fileList: UploadFileItem[]) => any) | undefined;
213
213
  onExceed?: ((files: File[], fileList: UploadFileItem[]) => any) | undefined;
214
214
  }>, {
215
- data: Record<string, any>;
216
215
  disabled: boolean;
216
+ data: Record<string, any>;
217
217
  multiple: boolean;
218
- maxSize: number;
219
218
  draggable: boolean;
219
+ maxSize: number;
220
220
  action: string;
221
221
  headers: Record<string, string>;
222
222
  directory: boolean;
@@ -259,9 +259,9 @@ type PlayerInstance = InstanceType<typeof xgplayer.default>;
259
259
  //#endregion
260
260
  //#region src/components/C_VideoPlayer/index.vue.d.ts
261
261
  declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
262
- ready: () => any;
263
262
  error: (error: Error) => any;
264
263
  ended: () => any;
264
+ ready: () => any;
265
265
  stateChange: (state: PlayerState) => any;
266
266
  timeUpdate: (currentTime: number, duration: number) => any;
267
267
  qualityChange: (quality: QualityLevel) => any;
@@ -272,9 +272,9 @@ declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExp
272
272
  chapterChange: (chapter: Chapter) => any;
273
273
  progressUpdate: (data: ProgressData) => any;
274
274
  }, string, vue.PublicProps, Readonly<VideoPlayerProps> & Readonly<{
275
- onReady?: (() => any) | undefined;
276
275
  onError?: ((error: Error) => any) | undefined;
277
276
  onEnded?: (() => any) | undefined;
277
+ onReady?: (() => any) | undefined;
278
278
  onStateChange?: ((state: PlayerState) => any) | undefined;
279
279
  onTimeUpdate?: ((currentTime: number, duration: number) => any) | undefined;
280
280
  onQualityChange?: ((quality: QualityLevel) => any) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["hljs","javascript","typescript","json","xml","css","bash","yaml","markdown","java","csharp","go","python","C_Code","C_Icon","C_Upload","C_Barcode","C_Captcha","C_Cascade","C_Guide","C_Progress","C_Steps","C_ActionBar","C_Theme","C_Language","C_Date","C_Editor","C_Markdown","C_Map","C_City","C_VtableGantt","C_Signature","C_SplitPane","C_CollapsePanel","C_Time","C_FormSearch","C_Tree","C_QRCode","C_ImageCropper","C_Draggable","C_WaterFall","C_FullCalendar","C_NotificationCenter","C_Cron","C_FormulaEditor","C_AntV","C_VideoPlayer","C_FilePreview","C_WorkFlow","C_Form","C_Table","C_GlobalSearch","C_Menu","C_Breadcrumb","C_TagsView"],"sources":["../src/plugins/highlight.ts","../src/index.ts"],"sourcesContent":["\r\n\r\nimport type { App } from 'vue'\r\nimport type { HLJSApi, LanguageFn } from 'highlight.js'\r\nimport hljs from 'highlight.js/lib/core'\r\n\r\n// 导入默认主题样式\r\nimport 'highlight.js/styles/github.css'\r\n\r\n// 默认支持的语言包(常用语言预加载)\r\nimport javascript from 'highlight.js/lib/languages/javascript'\r\nimport typescript from 'highlight.js/lib/languages/typescript'\r\nimport json from 'highlight.js/lib/languages/json'\r\nimport xml from 'highlight.js/lib/languages/xml' // HTML\r\nimport css from 'highlight.js/lib/languages/css'\r\nimport bash from 'highlight.js/lib/languages/bash'\r\nimport yaml from 'highlight.js/lib/languages/yaml'\r\nimport markdown from 'highlight.js/lib/languages/markdown'\r\nimport java from 'highlight.js/lib/languages/java'\r\nimport csharp from 'highlight.js/lib/languages/csharp'\r\nimport go from 'highlight.js/lib/languages/go'\r\nimport python from 'highlight.js/lib/languages/python'\r\n\r\n// 可选语言包映射(懒加载)\r\nconst OPTIONAL_LANGUAGES: Record<\r\n string,\r\n () => Promise<{ default: LanguageFn }>\r\n> = {\r\n cpp: () => import('highlight.js/lib/languages/cpp'),\r\n c: () => import('highlight.js/lib/languages/c'),\r\n php: () => import('highlight.js/lib/languages/php'),\r\n ruby: () => import('highlight.js/lib/languages/ruby'),\r\n rust: () => import('highlight.js/lib/languages/rust'),\r\n swift: () => import('highlight.js/lib/languages/swift'),\r\n kotlin: () => import('highlight.js/lib/languages/kotlin'),\r\n scss: () => import('highlight.js/lib/languages/scss'),\r\n less: () => import('highlight.js/lib/languages/less'),\r\n sql: () => import('highlight.js/lib/languages/sql'),\r\n dockerfile: () => import('highlight.js/lib/languages/dockerfile'),\r\n powershell: () => import('highlight.js/lib/languages/powershell'),\r\n}\r\n\r\n// 插件配置选项\r\nexport interface HighlightPluginOptions {\r\n autoDetect?: boolean\r\n extraLanguages?: string[]\r\n}\r\n\r\n// 状态管理\r\nconst loadedLanguages = new Set<string>()\r\nconst hlJsInstance: HLJSApi = hljs\r\n\r\n/**\r\n * * @description 注册语言包到 highlight.js 实例\r\n * ? @param name - 语言名称\r\n * ? @param languageFn - 语言定义函数\r\n * ! @return void\r\n */\r\nfunction registerLanguage(name: string, languageFn: LanguageFn): void {\r\n hlJsInstance.registerLanguage(name, languageFn)\r\n loadedLanguages.add(name)\r\n}\r\n\r\n/**\r\n * * @description 初始化核心配置,注册默认语言包\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nfunction initializeCore(options: HighlightPluginOptions): void {\r\n // 注册默认语言包\r\n const defaultLanguages = [\r\n ['javascript', javascript],\r\n ['typescript', typescript],\r\n ['json', json],\r\n ['html', xml],\r\n ['xml', xml],\r\n ['css', css],\r\n ['bash', bash],\r\n ['shell', bash],\r\n ['yaml', yaml],\r\n ['yml', yaml],\r\n ['markdown', markdown],\r\n ['java', java],\r\n ['csharp', csharp],\r\n ['go', go],\r\n ['python', python],\r\n ] as const\r\n\r\n defaultLanguages.forEach(([name, langFn]) => {\r\n registerLanguage(name, langFn)\r\n })\r\n\r\n // 配置 highlight.js\r\n hlJsInstance.configure({\r\n ignoreUnescapedHTML: true,\r\n languages: options.autoDetect ? undefined : [],\r\n })\r\n\r\n // 预加载额外语言\r\n if (options.extraLanguages?.length) {\r\n loadLanguages(options.extraLanguages)\r\n }\r\n}\r\n\r\n/**\r\n * * @description 批量加载多个语言包\r\n * ? @param languages - 要加载的语言名称数组\r\n * ! @return Promise<string[]> 成功加载的语言名称数组\r\n */\r\nasync function loadLanguages(languages: string[]): Promise<string[]> {\r\n const loadPromises = languages.map(lang => loadLanguage(lang))\r\n const results = await Promise.allSettled(loadPromises)\r\n\r\n return results\r\n .map((result, index) =>\r\n result.status === 'fulfilled' ? languages[index] : null\r\n )\r\n .filter(Boolean) as string[]\r\n}\r\n\r\n/**\r\n * * @description 动态加载单个语言包\r\n * ? @param language - 要加载的语言名称\r\n * ! @return Promise<boolean> 是否加载成功\r\n */\r\nasync function loadLanguage(language: string): Promise<boolean> {\r\n if (loadedLanguages.has(language)) {\r\n return true\r\n }\r\n\r\n const loader = OPTIONAL_LANGUAGES[language.toLowerCase()]\r\n if (!loader) {\r\n console.warn(`[HighlightPlugin] Language '${language}' not supported`)\r\n return false\r\n }\r\n\r\n try {\r\n const languageModule = await loader()\r\n registerLanguage(language, languageModule.default)\r\n console.log(`[HighlightPlugin] Language '${language}' loaded successfully`)\r\n return true\r\n } catch (error) {\r\n console.error(\r\n `[HighlightPlugin] Failed to load language '${language}':`,\r\n error\r\n )\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * * @description 获取 highlight 功能的 API 接口\r\n * ! @return highlight API 对象,包含所有可用方法\r\n */\r\nexport const useHighlight = () => {\r\n return {\r\n // 核心方法\r\n getHljs: () => hlJsInstance,\r\n\r\n // 语言管理\r\n loadLanguage: (language: string) => loadLanguage(language),\r\n loadLanguages: (languages: string[]) => loadLanguages(languages),\r\n getLoadedLanguages: () => Array.from(loadedLanguages),\r\n }\r\n}\r\n\r\n/**\r\n * * @description 安装 highlight.js 插件到 Vue 应用\r\n * ? @param app - Vue 应用实例\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nexport function setupHighlight(app: App, options: HighlightPluginOptions = {}) {\r\n const pluginOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n ...options,\r\n }\r\n\r\n // 初始化核心配置\r\n initializeCore(pluginOptions)\r\n\r\n // 挂载到全局\r\n if (typeof window !== 'undefined') {\r\n window.hljs = hlJsInstance\r\n }\r\n\r\n // 提供给 Vue 应用\r\n const highlightAPI = useHighlight()\r\n app.provide('highlightManager', highlightAPI)\r\n app.config.globalProperties.$highlight = highlightAPI\r\n\r\n console.log('[HighlightPlugin] 🎨 highlight.js plugin installed successfully')\r\n}\r\n\r\n// 导出默认配置\r\nexport const defaultHighlightOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n}\r\n\r\n// 类型声明\r\ndeclare global {\r\n interface Window {\r\n hljs: HLJSApi\r\n }\r\n}\r\n","import type { App, Component } from 'vue'\n\n// ====== 全局样式由 sass CLI 编译到 dist/style.css,不再通过 JS 导入 ======\n\n// ====== 组件导入(仅用于 install 全量注册) ======\nimport { C_Code } from './components/C_Code'\nimport { C_Icon } from './components/C_Icon'\nimport { C_Upload } from './components/C_Upload'\nimport { C_Barcode } from './components/C_Barcode'\nimport { C_Captcha } from './components/C_Captcha'\nimport { C_Cascade } from './components/C_Cascade'\nimport { C_Guide } from './components/C_Guide'\nimport { C_Progress } from './components/C_Progress'\nimport { C_Steps } from './components/C_Steps'\nimport { C_ActionBar } from './components/C_ActionBar'\nimport { C_Theme } from './components/C_Theme'\nimport { C_Language } from './components/C_Language'\nimport { C_Date } from './components/C_Date'\nimport { C_Editor } from './components/C_Editor'\nimport { C_Markdown } from './components/C_Markdown'\nimport { C_Map } from './components/C_Map'\nimport { C_City } from './components/C_City'\nimport { C_VtableGantt } from './components/C_VtableGantt'\nimport { C_Signature } from './components/C_Signature'\nimport { C_SplitPane } from './components/C_SplitPane'\nimport { C_CollapsePanel } from './components/C_CollapsePanel'\nimport { C_Time } from './components/C_Time'\nimport { C_FormSearch } from './components/C_FormSearch'\nimport { C_Tree } from './components/C_Tree'\nimport { C_QRCode } from './components/C_QRCode'\nimport { C_ImageCropper } from './components/C_ImageCropper'\nimport { C_Draggable } from './components/C_Draggable'\nimport { C_WaterFall } from './components/C_WaterFall'\nimport { C_FullCalendar } from './components/C_FullCalendar'\nimport { C_NotificationCenter } from './components/C_NotificationCenter'\nimport { C_Cron } from './components/C_Cron'\nimport { C_FormulaEditor } from './components/C_FormulaEditor'\nimport { C_AntV } from './components/C_AntV'\nimport { C_VideoPlayer } from './components/C_VideoPlayer'\nimport { C_FilePreview } from './components/C_FilePreview'\nimport { C_WorkFlow } from './components/C_WorkFlow'\nimport { C_Form } from './components/C_Form'\nimport { C_Table } from './components/C_Table'\nimport { C_GlobalSearch } from './components/C_GlobalSearch'\nimport { C_Menu } from './components/C_Menu'\nimport { C_Breadcrumb } from './components/C_Breadcrumb'\nimport { C_TagsView } from './components/C_TagsView'\n\n// ====== 插件 ======\nimport { setupHighlight, useHighlight } from './plugins/highlight'\n\n// ====== 安装选项 ======\nexport interface ComponentLibOptions {\n highlight?: import('./plugins/highlight').HighlightPluginOptions\n}\n\n// ====== 组件列表(全量注册使用) ======\nconst components: Component[] = [\n C_Code,\n C_Icon,\n C_Upload,\n C_Barcode,\n C_Captcha,\n C_Cascade,\n C_Guide,\n C_Progress,\n C_Steps,\n C_ActionBar,\n C_Theme,\n C_Language,\n C_Date,\n C_Editor,\n C_Markdown,\n C_Map,\n C_City,\n C_VtableGantt,\n C_Signature,\n C_SplitPane,\n C_CollapsePanel,\n C_Time,\n C_FormSearch,\n C_Tree,\n C_QRCode,\n C_ImageCropper,\n C_Draggable,\n C_WaterFall,\n C_FullCalendar,\n C_NotificationCenter,\n C_Cron,\n C_FormulaEditor,\n C_AntV,\n C_VideoPlayer,\n C_FilePreview,\n C_WorkFlow,\n C_Form,\n C_Table,\n C_GlobalSearch,\n C_Menu,\n C_Breadcrumb,\n C_TagsView,\n]\n\n// ====== Barrel Re-exports:所有组件 + composables + types + constants ======\nexport * from './components/C_Code'\nexport * from './components/C_Icon'\nexport * from './components/C_Upload'\nexport * from './components/C_Barcode'\nexport * from './components/C_Captcha'\nexport * from './components/C_Cascade'\nexport * from './components/C_Guide'\nexport * from './components/C_Progress'\nexport * from './components/C_Steps'\nexport * from './components/C_ActionBar'\nexport * from './components/C_Theme'\nexport * from './components/C_Language'\nexport * from './components/C_Date'\nexport * from './components/C_Editor'\nexport * from './components/C_Markdown'\nexport * from './components/C_Map'\nexport * from './components/C_City'\nexport * from './components/C_VtableGantt'\nexport * from './components/C_Signature'\nexport * from './components/C_SplitPane'\nexport * from './components/C_CollapsePanel'\nexport * from './components/C_Time'\nexport * from './components/C_FormSearch'\nexport * from './components/C_Tree'\nexport * from './components/C_QRCode'\nexport * from './components/C_ImageCropper'\nexport * from './components/C_Draggable'\nexport * from './components/C_WaterFall'\nexport * from './components/C_FullCalendar'\nexport * from './components/C_NotificationCenter'\nexport * from './components/C_Cron'\nexport * from './components/C_FormulaEditor'\nexport * from './components/C_AntV'\nexport * from './components/C_VideoPlayer'\nexport * from './components/C_FilePreview'\nexport * from './components/C_WorkFlow'\nexport * from './components/C_Form'\nexport * from './components/C_Table'\nexport * from './components/C_GlobalSearch'\nexport * from './components/C_Menu'\nexport * from './components/C_Breadcrumb'\nexport * from './components/C_TagsView'\n\n// ====== 共享类型 + 适配器 ======\nexport * from './components/_shared'\n\n// ====== 工具函数(不属于任何组件的公共工具) ======\nexport { setItem, getItem, removeItem, removeAllItem } from './utils/storage'\n\n// ====== 插件导出 ======\nexport { setupHighlight, useHighlight }\nexport type { HighlightPluginOptions } from './plugins/highlight'\n\n// ====== 全量安装 ======\nconst install = (app: App, options: ComponentLibOptions = {}) => {\n components.forEach(component => {\n const name =\n (component as any).__name || (component as any).name || 'UnknownComponent'\n app.component(name, component)\n })\n\n if (options.highlight !== undefined) {\n setupHighlight(app, options.highlight)\n }\n}\n\nexport default {\n install,\n} satisfies { install: (app: App, options?: ComponentLibOptions) => void }\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["hljs","javascript","typescript","json","xml","css","bash","yaml","markdown","java","csharp","go","python","C_Code","C_Icon","C_Upload","C_Barcode","C_Captcha","C_Cascade","C_Guide","C_Progress","C_Steps","C_ActionBar","C_Theme","C_Language","C_Date","C_Editor","C_Markdown","C_Map","C_City","C_VtableGantt","C_Signature","C_SplitPane","C_CollapsePanel","C_Time","C_FormSearch","C_Tree","C_QRCode","C_ImageCropper","C_Draggable","C_WaterFall","C_FullCalendar","C_NotificationCenter","C_Cron","C_FormulaEditor","C_AntV","C_VideoPlayer","C_FilePreview","C_WorkFlow","C_Form","C_Table","C_GlobalSearch","C_Menu","C_Breadcrumb","C_TagsView"],"sources":["../src/plugins/highlight.ts","../src/index.ts"],"sourcesContent":["\r\n\r\nimport type { App } from 'vue'\r\nimport type { HLJSApi, LanguageFn } from 'highlight.js'\r\nimport hljs from 'highlight.js/lib/core'\r\n\r\n// 导入默认主题样式\r\nimport 'highlight.js/styles/github.css'\r\n\r\n// 默认支持的语言包(常用语言预加载)\r\nimport javascript from 'highlight.js/lib/languages/javascript'\r\nimport typescript from 'highlight.js/lib/languages/typescript'\r\nimport json from 'highlight.js/lib/languages/json'\r\nimport xml from 'highlight.js/lib/languages/xml' // HTML\r\nimport css from 'highlight.js/lib/languages/css'\r\nimport bash from 'highlight.js/lib/languages/bash'\r\nimport yaml from 'highlight.js/lib/languages/yaml'\r\nimport markdown from 'highlight.js/lib/languages/markdown'\r\nimport java from 'highlight.js/lib/languages/java'\r\nimport csharp from 'highlight.js/lib/languages/csharp'\r\nimport go from 'highlight.js/lib/languages/go'\r\nimport python from 'highlight.js/lib/languages/python'\r\n\r\n// 可选语言包映射(懒加载)\r\nconst OPTIONAL_LANGUAGES: Record<\r\n string,\r\n () => Promise<{ default: LanguageFn }>\r\n> = {\r\n cpp: () => import('highlight.js/lib/languages/cpp'),\r\n c: () => import('highlight.js/lib/languages/c'),\r\n php: () => import('highlight.js/lib/languages/php'),\r\n ruby: () => import('highlight.js/lib/languages/ruby'),\r\n rust: () => import('highlight.js/lib/languages/rust'),\r\n swift: () => import('highlight.js/lib/languages/swift'),\r\n kotlin: () => import('highlight.js/lib/languages/kotlin'),\r\n scss: () => import('highlight.js/lib/languages/scss'),\r\n less: () => import('highlight.js/lib/languages/less'),\r\n sql: () => import('highlight.js/lib/languages/sql'),\r\n dockerfile: () => import('highlight.js/lib/languages/dockerfile'),\r\n powershell: () => import('highlight.js/lib/languages/powershell'),\r\n}\r\n\r\n// 插件配置选项\r\nexport interface HighlightPluginOptions {\r\n autoDetect?: boolean\r\n extraLanguages?: string[]\r\n}\r\n\r\n// 状态管理\r\nconst loadedLanguages = new Set<string>()\r\nconst hlJsInstance: HLJSApi = hljs\r\n\r\n/**\r\n * * @description 注册语言包到 highlight.js 实例\r\n * ? @param name - 语言名称\r\n * ? @param languageFn - 语言定义函数\r\n * ! @return void\r\n */\r\nfunction registerLanguage(name: string, languageFn: LanguageFn): void {\r\n hlJsInstance.registerLanguage(name, languageFn)\r\n loadedLanguages.add(name)\r\n}\r\n\r\n/**\r\n * * @description 初始化核心配置,注册默认语言包\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nfunction initializeCore(options: HighlightPluginOptions): void {\r\n // 注册默认语言包\r\n const defaultLanguages = [\r\n ['javascript', javascript],\r\n ['typescript', typescript],\r\n ['json', json],\r\n ['html', xml],\r\n ['xml', xml],\r\n ['css', css],\r\n ['bash', bash],\r\n ['shell', bash],\r\n ['yaml', yaml],\r\n ['yml', yaml],\r\n ['markdown', markdown],\r\n ['java', java],\r\n ['csharp', csharp],\r\n ['go', go],\r\n ['python', python],\r\n ] as const\r\n\r\n defaultLanguages.forEach(([name, langFn]) => {\r\n registerLanguage(name, langFn)\r\n })\r\n\r\n // 配置 highlight.js\r\n hlJsInstance.configure({\r\n ignoreUnescapedHTML: true,\r\n languages: options.autoDetect ? undefined : [],\r\n })\r\n\r\n // 预加载额外语言\r\n if (options.extraLanguages?.length) {\r\n loadLanguages(options.extraLanguages)\r\n }\r\n}\r\n\r\n/**\r\n * * @description 批量加载多个语言包\r\n * ? @param languages - 要加载的语言名称数组\r\n * ! @return Promise<string[]> 成功加载的语言名称数组\r\n */\r\nasync function loadLanguages(languages: string[]): Promise<string[]> {\r\n const loadPromises = languages.map(lang => loadLanguage(lang))\r\n const results = await Promise.allSettled(loadPromises)\r\n\r\n return results\r\n .map((result, index) =>\r\n result.status === 'fulfilled' ? languages[index] : null\r\n )\r\n .filter(Boolean) as string[]\r\n}\r\n\r\n/**\r\n * * @description 动态加载单个语言包\r\n * ? @param language - 要加载的语言名称\r\n * ! @return Promise<boolean> 是否加载成功\r\n */\r\nasync function loadLanguage(language: string): Promise<boolean> {\r\n if (loadedLanguages.has(language)) {\r\n return true\r\n }\r\n\r\n const loader = OPTIONAL_LANGUAGES[language.toLowerCase()]\r\n if (!loader) {\r\n console.warn(`[HighlightPlugin] Language '${language}' not supported`)\r\n return false\r\n }\r\n\r\n try {\r\n const languageModule = await loader()\r\n registerLanguage(language, languageModule.default)\r\n console.log(`[HighlightPlugin] Language '${language}' loaded successfully`)\r\n return true\r\n } catch (error) {\r\n console.error(\r\n `[HighlightPlugin] Failed to load language '${language}':`,\r\n error\r\n )\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * * @description 获取 highlight 功能的 API 接口\r\n * ! @return highlight API 对象,包含所有可用方法\r\n */\r\nexport const useHighlight = () => {\r\n return {\r\n // 核心方法\r\n getHljs: () => hlJsInstance,\r\n\r\n // 语言管理\r\n loadLanguage: (language: string) => loadLanguage(language),\r\n loadLanguages: (languages: string[]) => loadLanguages(languages),\r\n getLoadedLanguages: () => Array.from(loadedLanguages),\r\n }\r\n}\r\n\r\n/**\r\n * * @description 安装 highlight.js 插件到 Vue 应用\r\n * ? @param app - Vue 应用实例\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nexport function setupHighlight(app: App, options: HighlightPluginOptions = {}) {\r\n const pluginOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n ...options,\r\n }\r\n\r\n // 初始化核心配置\r\n initializeCore(pluginOptions)\r\n\r\n // 挂载到全局\r\n if (typeof window !== 'undefined') {\r\n window.hljs = hlJsInstance\r\n }\r\n\r\n // 提供给 Vue 应用\r\n const highlightAPI = useHighlight()\r\n app.provide('highlightManager', highlightAPI)\r\n app.config.globalProperties.$highlight = highlightAPI\r\n\r\n console.log('[HighlightPlugin] 🎨 highlight.js plugin installed successfully')\r\n}\r\n\r\n// 导出默认配置\r\nexport const defaultHighlightOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n}\r\n\r\n// 类型声明\r\ndeclare global {\r\n interface Window {\r\n hljs: HLJSApi\r\n }\r\n}\r\n","import type { App, Component } from 'vue'\r\n\r\n// ====== 全局样式由 sass CLI 编译到 dist/style.css,不再通过 JS 导入 ======\r\n\r\n// ====== 组件导入(仅用于 install 全量注册) ======\r\nimport { C_Code } from './components/C_Code'\r\nimport { C_Icon } from './components/C_Icon'\r\nimport { C_Upload } from './components/C_Upload'\r\nimport { C_Barcode } from './components/C_Barcode'\r\nimport { C_Captcha } from './components/C_Captcha'\r\nimport { C_Cascade } from './components/C_Cascade'\r\nimport { C_Guide } from './components/C_Guide'\r\nimport { C_Progress } from './components/C_Progress'\r\nimport { C_Steps } from './components/C_Steps'\r\nimport { C_ActionBar } from './components/C_ActionBar'\r\nimport { C_Theme } from './components/C_Theme'\r\nimport { C_Language } from './components/C_Language'\r\nimport { C_Date } from './components/C_Date'\r\nimport { C_Editor } from './components/C_Editor'\r\nimport { C_Markdown } from './components/C_Markdown'\r\nimport { C_Map } from './components/C_Map'\r\nimport { C_City } from './components/C_City'\r\nimport { C_VtableGantt } from './components/C_VtableGantt'\r\nimport { C_Signature } from './components/C_Signature'\r\nimport { C_SplitPane } from './components/C_SplitPane'\r\nimport { C_CollapsePanel } from './components/C_CollapsePanel'\r\nimport { C_Time } from './components/C_Time'\r\nimport { C_FormSearch } from './components/C_FormSearch'\r\nimport { C_Tree } from './components/C_Tree'\r\nimport { C_QRCode } from './components/C_QRCode'\r\nimport { C_ImageCropper } from './components/C_ImageCropper'\r\nimport { C_Draggable } from './components/C_Draggable'\r\nimport { C_WaterFall } from './components/C_WaterFall'\r\nimport { C_FullCalendar } from './components/C_FullCalendar'\r\nimport { C_NotificationCenter } from './components/C_NotificationCenter'\r\nimport { C_Cron } from './components/C_Cron'\r\nimport { C_FormulaEditor } from './components/C_FormulaEditor'\r\nimport { C_AntV } from './components/C_AntV'\r\nimport { C_VideoPlayer } from './components/C_VideoPlayer'\r\nimport { C_FilePreview } from './components/C_FilePreview'\r\nimport { C_WorkFlow } from './components/C_WorkFlow'\r\nimport { C_Form } from './components/C_Form'\r\nimport { C_Table } from './components/C_Table'\r\nimport { C_GlobalSearch } from './components/C_GlobalSearch'\r\nimport { C_Menu } from './components/C_Menu'\r\nimport { C_Breadcrumb } from './components/C_Breadcrumb'\r\nimport { C_TagsView } from './components/C_TagsView'\r\n\r\n// ====== 插件 ======\r\nimport { setupHighlight, useHighlight } from './plugins/highlight'\r\n\r\n// ====== 安装选项 ======\r\nexport interface ComponentLibOptions {\r\n highlight?: import('./plugins/highlight').HighlightPluginOptions\r\n}\r\n\r\n// ====== 组件列表(全量注册使用) ======\r\nconst components: Component[] = [\r\n C_Code,\r\n C_Icon,\r\n C_Upload,\r\n C_Barcode,\r\n C_Captcha,\r\n C_Cascade,\r\n C_Guide,\r\n C_Progress,\r\n C_Steps,\r\n C_ActionBar,\r\n C_Theme,\r\n C_Language,\r\n C_Date,\r\n C_Editor,\r\n C_Markdown,\r\n C_Map,\r\n C_City,\r\n C_VtableGantt,\r\n C_Signature,\r\n C_SplitPane,\r\n C_CollapsePanel,\r\n C_Time,\r\n C_FormSearch,\r\n C_Tree,\r\n C_QRCode,\r\n C_ImageCropper,\r\n C_Draggable,\r\n C_WaterFall,\r\n C_FullCalendar,\r\n C_NotificationCenter,\r\n C_Cron,\r\n C_FormulaEditor,\r\n C_AntV,\r\n C_VideoPlayer,\r\n C_FilePreview,\r\n C_WorkFlow,\r\n C_Form,\r\n C_Table,\r\n C_GlobalSearch,\r\n C_Menu,\r\n C_Breadcrumb,\r\n C_TagsView,\r\n]\r\n\r\n// ====== Barrel Re-exports:所有组件 + composables + types + constants ======\r\nexport * from './components/C_Code'\r\nexport * from './components/C_Icon'\r\nexport * from './components/C_Upload'\r\nexport * from './components/C_Barcode'\r\nexport * from './components/C_Captcha'\r\nexport * from './components/C_Cascade'\r\nexport * from './components/C_Guide'\r\nexport * from './components/C_Progress'\r\nexport * from './components/C_Steps'\r\nexport * from './components/C_ActionBar'\r\nexport * from './components/C_Theme'\r\nexport * from './components/C_Language'\r\nexport * from './components/C_Date'\r\nexport * from './components/C_Editor'\r\nexport * from './components/C_Markdown'\r\nexport * from './components/C_Map'\r\nexport * from './components/C_City'\r\nexport * from './components/C_VtableGantt'\r\nexport * from './components/C_Signature'\r\nexport * from './components/C_SplitPane'\r\nexport * from './components/C_CollapsePanel'\r\nexport * from './components/C_Time'\r\nexport * from './components/C_FormSearch'\r\nexport * from './components/C_Tree'\r\nexport * from './components/C_QRCode'\r\nexport * from './components/C_ImageCropper'\r\nexport * from './components/C_Draggable'\r\nexport * from './components/C_WaterFall'\r\nexport * from './components/C_FullCalendar'\r\nexport * from './components/C_NotificationCenter'\r\nexport * from './components/C_Cron'\r\nexport * from './components/C_FormulaEditor'\r\nexport * from './components/C_AntV'\r\nexport * from './components/C_VideoPlayer'\r\nexport * from './components/C_FilePreview'\r\nexport * from './components/C_WorkFlow'\r\nexport * from './components/C_Form'\r\nexport * from './components/C_Table'\r\nexport * from './components/C_GlobalSearch'\r\nexport * from './components/C_Menu'\r\nexport * from './components/C_Breadcrumb'\r\nexport * from './components/C_TagsView'\r\n\r\n// ====== 共享类型 + 适配器 ======\r\nexport * from './components/_shared'\r\n\r\n// ====== 工具函数(不属于任何组件的公共工具) ======\r\nexport { setItem, getItem, removeItem, removeAllItem } from './utils/storage'\r\n\r\n// ====== 插件导出 ======\r\nexport { setupHighlight, useHighlight }\r\nexport type { HighlightPluginOptions } from './plugins/highlight'\r\n\r\n// ====== 全量安装 ======\r\nconst install = (app: App, options: ComponentLibOptions = {}) => {\r\n components.forEach(component => {\r\n const name =\r\n (component as any).__name || (component as any).name || 'UnknownComponent'\r\n app.component(name, component)\r\n })\r\n\r\n if (options.highlight !== undefined) {\r\n setupHighlight(app, options.highlight)\r\n }\r\n}\r\n\r\nexport default {\r\n install,\r\n} satisfies { install: (app: App, options?: ComponentLibOptions) => void }\r\n"],"mappings":"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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["C_Code","C_Icon","C_Upload","C_Barcode","C_Captcha","C_Cascade","C_Guide","C_Progress","C_Steps","C_ActionBar","C_Theme","C_Language","C_Date","C_Editor","C_Markdown","C_Map","C_City","C_VtableGantt","C_Signature","C_SplitPane","C_CollapsePanel","C_Time","C_FormSearch","C_Tree","C_QRCode","C_ImageCropper","C_Draggable","C_WaterFall","C_FullCalendar","C_NotificationCenter","C_Cron","C_FormulaEditor","C_AntV","C_VideoPlayer","C_FilePreview","C_WorkFlow","C_Form","C_Table","C_GlobalSearch","C_Menu","C_Breadcrumb","C_TagsView"],"sources":["../src/plugins/highlight.ts","../src/index.ts"],"sourcesContent":["\r\n\r\nimport type { App } from 'vue'\r\nimport type { HLJSApi, LanguageFn } from 'highlight.js'\r\nimport hljs from 'highlight.js/lib/core'\r\n\r\n// 导入默认主题样式\r\nimport 'highlight.js/styles/github.css'\r\n\r\n// 默认支持的语言包(常用语言预加载)\r\nimport javascript from 'highlight.js/lib/languages/javascript'\r\nimport typescript from 'highlight.js/lib/languages/typescript'\r\nimport json from 'highlight.js/lib/languages/json'\r\nimport xml from 'highlight.js/lib/languages/xml' // HTML\r\nimport css from 'highlight.js/lib/languages/css'\r\nimport bash from 'highlight.js/lib/languages/bash'\r\nimport yaml from 'highlight.js/lib/languages/yaml'\r\nimport markdown from 'highlight.js/lib/languages/markdown'\r\nimport java from 'highlight.js/lib/languages/java'\r\nimport csharp from 'highlight.js/lib/languages/csharp'\r\nimport go from 'highlight.js/lib/languages/go'\r\nimport python from 'highlight.js/lib/languages/python'\r\n\r\n// 可选语言包映射(懒加载)\r\nconst OPTIONAL_LANGUAGES: Record<\r\n string,\r\n () => Promise<{ default: LanguageFn }>\r\n> = {\r\n cpp: () => import('highlight.js/lib/languages/cpp'),\r\n c: () => import('highlight.js/lib/languages/c'),\r\n php: () => import('highlight.js/lib/languages/php'),\r\n ruby: () => import('highlight.js/lib/languages/ruby'),\r\n rust: () => import('highlight.js/lib/languages/rust'),\r\n swift: () => import('highlight.js/lib/languages/swift'),\r\n kotlin: () => import('highlight.js/lib/languages/kotlin'),\r\n scss: () => import('highlight.js/lib/languages/scss'),\r\n less: () => import('highlight.js/lib/languages/less'),\r\n sql: () => import('highlight.js/lib/languages/sql'),\r\n dockerfile: () => import('highlight.js/lib/languages/dockerfile'),\r\n powershell: () => import('highlight.js/lib/languages/powershell'),\r\n}\r\n\r\n// 插件配置选项\r\nexport interface HighlightPluginOptions {\r\n autoDetect?: boolean\r\n extraLanguages?: string[]\r\n}\r\n\r\n// 状态管理\r\nconst loadedLanguages = new Set<string>()\r\nconst hlJsInstance: HLJSApi = hljs\r\n\r\n/**\r\n * * @description 注册语言包到 highlight.js 实例\r\n * ? @param name - 语言名称\r\n * ? @param languageFn - 语言定义函数\r\n * ! @return void\r\n */\r\nfunction registerLanguage(name: string, languageFn: LanguageFn): void {\r\n hlJsInstance.registerLanguage(name, languageFn)\r\n loadedLanguages.add(name)\r\n}\r\n\r\n/**\r\n * * @description 初始化核心配置,注册默认语言包\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nfunction initializeCore(options: HighlightPluginOptions): void {\r\n // 注册默认语言包\r\n const defaultLanguages = [\r\n ['javascript', javascript],\r\n ['typescript', typescript],\r\n ['json', json],\r\n ['html', xml],\r\n ['xml', xml],\r\n ['css', css],\r\n ['bash', bash],\r\n ['shell', bash],\r\n ['yaml', yaml],\r\n ['yml', yaml],\r\n ['markdown', markdown],\r\n ['java', java],\r\n ['csharp', csharp],\r\n ['go', go],\r\n ['python', python],\r\n ] as const\r\n\r\n defaultLanguages.forEach(([name, langFn]) => {\r\n registerLanguage(name, langFn)\r\n })\r\n\r\n // 配置 highlight.js\r\n hlJsInstance.configure({\r\n ignoreUnescapedHTML: true,\r\n languages: options.autoDetect ? undefined : [],\r\n })\r\n\r\n // 预加载额外语言\r\n if (options.extraLanguages?.length) {\r\n loadLanguages(options.extraLanguages)\r\n }\r\n}\r\n\r\n/**\r\n * * @description 批量加载多个语言包\r\n * ? @param languages - 要加载的语言名称数组\r\n * ! @return Promise<string[]> 成功加载的语言名称数组\r\n */\r\nasync function loadLanguages(languages: string[]): Promise<string[]> {\r\n const loadPromises = languages.map(lang => loadLanguage(lang))\r\n const results = await Promise.allSettled(loadPromises)\r\n\r\n return results\r\n .map((result, index) =>\r\n result.status === 'fulfilled' ? languages[index] : null\r\n )\r\n .filter(Boolean) as string[]\r\n}\r\n\r\n/**\r\n * * @description 动态加载单个语言包\r\n * ? @param language - 要加载的语言名称\r\n * ! @return Promise<boolean> 是否加载成功\r\n */\r\nasync function loadLanguage(language: string): Promise<boolean> {\r\n if (loadedLanguages.has(language)) {\r\n return true\r\n }\r\n\r\n const loader = OPTIONAL_LANGUAGES[language.toLowerCase()]\r\n if (!loader) {\r\n console.warn(`[HighlightPlugin] Language '${language}' not supported`)\r\n return false\r\n }\r\n\r\n try {\r\n const languageModule = await loader()\r\n registerLanguage(language, languageModule.default)\r\n console.log(`[HighlightPlugin] Language '${language}' loaded successfully`)\r\n return true\r\n } catch (error) {\r\n console.error(\r\n `[HighlightPlugin] Failed to load language '${language}':`,\r\n error\r\n )\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * * @description 获取 highlight 功能的 API 接口\r\n * ! @return highlight API 对象,包含所有可用方法\r\n */\r\nexport const useHighlight = () => {\r\n return {\r\n // 核心方法\r\n getHljs: () => hlJsInstance,\r\n\r\n // 语言管理\r\n loadLanguage: (language: string) => loadLanguage(language),\r\n loadLanguages: (languages: string[]) => loadLanguages(languages),\r\n getLoadedLanguages: () => Array.from(loadedLanguages),\r\n }\r\n}\r\n\r\n/**\r\n * * @description 安装 highlight.js 插件到 Vue 应用\r\n * ? @param app - Vue 应用实例\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nexport function setupHighlight(app: App, options: HighlightPluginOptions = {}) {\r\n const pluginOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n ...options,\r\n }\r\n\r\n // 初始化核心配置\r\n initializeCore(pluginOptions)\r\n\r\n // 挂载到全局\r\n if (typeof window !== 'undefined') {\r\n window.hljs = hlJsInstance\r\n }\r\n\r\n // 提供给 Vue 应用\r\n const highlightAPI = useHighlight()\r\n app.provide('highlightManager', highlightAPI)\r\n app.config.globalProperties.$highlight = highlightAPI\r\n\r\n console.log('[HighlightPlugin] 🎨 highlight.js plugin installed successfully')\r\n}\r\n\r\n// 导出默认配置\r\nexport const defaultHighlightOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n}\r\n\r\n// 类型声明\r\ndeclare global {\r\n interface Window {\r\n hljs: HLJSApi\r\n }\r\n}\r\n","import type { App, Component } from 'vue'\n\n// ====== 全局样式由 sass CLI 编译到 dist/style.css,不再通过 JS 导入 ======\n\n// ====== 组件导入(仅用于 install 全量注册) ======\nimport { C_Code } from './components/C_Code'\nimport { C_Icon } from './components/C_Icon'\nimport { C_Upload } from './components/C_Upload'\nimport { C_Barcode } from './components/C_Barcode'\nimport { C_Captcha } from './components/C_Captcha'\nimport { C_Cascade } from './components/C_Cascade'\nimport { C_Guide } from './components/C_Guide'\nimport { C_Progress } from './components/C_Progress'\nimport { C_Steps } from './components/C_Steps'\nimport { C_ActionBar } from './components/C_ActionBar'\nimport { C_Theme } from './components/C_Theme'\nimport { C_Language } from './components/C_Language'\nimport { C_Date } from './components/C_Date'\nimport { C_Editor } from './components/C_Editor'\nimport { C_Markdown } from './components/C_Markdown'\nimport { C_Map } from './components/C_Map'\nimport { C_City } from './components/C_City'\nimport { C_VtableGantt } from './components/C_VtableGantt'\nimport { C_Signature } from './components/C_Signature'\nimport { C_SplitPane } from './components/C_SplitPane'\nimport { C_CollapsePanel } from './components/C_CollapsePanel'\nimport { C_Time } from './components/C_Time'\nimport { C_FormSearch } from './components/C_FormSearch'\nimport { C_Tree } from './components/C_Tree'\nimport { C_QRCode } from './components/C_QRCode'\nimport { C_ImageCropper } from './components/C_ImageCropper'\nimport { C_Draggable } from './components/C_Draggable'\nimport { C_WaterFall } from './components/C_WaterFall'\nimport { C_FullCalendar } from './components/C_FullCalendar'\nimport { C_NotificationCenter } from './components/C_NotificationCenter'\nimport { C_Cron } from './components/C_Cron'\nimport { C_FormulaEditor } from './components/C_FormulaEditor'\nimport { C_AntV } from './components/C_AntV'\nimport { C_VideoPlayer } from './components/C_VideoPlayer'\nimport { C_FilePreview } from './components/C_FilePreview'\nimport { C_WorkFlow } from './components/C_WorkFlow'\nimport { C_Form } from './components/C_Form'\nimport { C_Table } from './components/C_Table'\nimport { C_GlobalSearch } from './components/C_GlobalSearch'\nimport { C_Menu } from './components/C_Menu'\nimport { C_Breadcrumb } from './components/C_Breadcrumb'\nimport { C_TagsView } from './components/C_TagsView'\n\n// ====== 插件 ======\nimport { setupHighlight, useHighlight } from './plugins/highlight'\n\n// ====== 安装选项 ======\nexport interface ComponentLibOptions {\n highlight?: import('./plugins/highlight').HighlightPluginOptions\n}\n\n// ====== 组件列表(全量注册使用) ======\nconst components: Component[] = [\n C_Code,\n C_Icon,\n C_Upload,\n C_Barcode,\n C_Captcha,\n C_Cascade,\n C_Guide,\n C_Progress,\n C_Steps,\n C_ActionBar,\n C_Theme,\n C_Language,\n C_Date,\n C_Editor,\n C_Markdown,\n C_Map,\n C_City,\n C_VtableGantt,\n C_Signature,\n C_SplitPane,\n C_CollapsePanel,\n C_Time,\n C_FormSearch,\n C_Tree,\n C_QRCode,\n C_ImageCropper,\n C_Draggable,\n C_WaterFall,\n C_FullCalendar,\n C_NotificationCenter,\n C_Cron,\n C_FormulaEditor,\n C_AntV,\n C_VideoPlayer,\n C_FilePreview,\n C_WorkFlow,\n C_Form,\n C_Table,\n C_GlobalSearch,\n C_Menu,\n C_Breadcrumb,\n C_TagsView,\n]\n\n// ====== Barrel Re-exports:所有组件 + composables + types + constants ======\nexport * from './components/C_Code'\nexport * from './components/C_Icon'\nexport * from './components/C_Upload'\nexport * from './components/C_Barcode'\nexport * from './components/C_Captcha'\nexport * from './components/C_Cascade'\nexport * from './components/C_Guide'\nexport * from './components/C_Progress'\nexport * from './components/C_Steps'\nexport * from './components/C_ActionBar'\nexport * from './components/C_Theme'\nexport * from './components/C_Language'\nexport * from './components/C_Date'\nexport * from './components/C_Editor'\nexport * from './components/C_Markdown'\nexport * from './components/C_Map'\nexport * from './components/C_City'\nexport * from './components/C_VtableGantt'\nexport * from './components/C_Signature'\nexport * from './components/C_SplitPane'\nexport * from './components/C_CollapsePanel'\nexport * from './components/C_Time'\nexport * from './components/C_FormSearch'\nexport * from './components/C_Tree'\nexport * from './components/C_QRCode'\nexport * from './components/C_ImageCropper'\nexport * from './components/C_Draggable'\nexport * from './components/C_WaterFall'\nexport * from './components/C_FullCalendar'\nexport * from './components/C_NotificationCenter'\nexport * from './components/C_Cron'\nexport * from './components/C_FormulaEditor'\nexport * from './components/C_AntV'\nexport * from './components/C_VideoPlayer'\nexport * from './components/C_FilePreview'\nexport * from './components/C_WorkFlow'\nexport * from './components/C_Form'\nexport * from './components/C_Table'\nexport * from './components/C_GlobalSearch'\nexport * from './components/C_Menu'\nexport * from './components/C_Breadcrumb'\nexport * from './components/C_TagsView'\n\n// ====== 共享类型 + 适配器 ======\nexport * from './components/_shared'\n\n// ====== 工具函数(不属于任何组件的公共工具) ======\nexport { setItem, getItem, removeItem, removeAllItem } from './utils/storage'\n\n// ====== 插件导出 ======\nexport { setupHighlight, useHighlight }\nexport type { HighlightPluginOptions } from './plugins/highlight'\n\n// ====== 全量安装 ======\nconst install = (app: App, options: ComponentLibOptions = {}) => {\n components.forEach(component => {\n const name =\n (component as any).__name || (component as any).name || 'UnknownComponent'\n app.component(name, component)\n })\n\n if (options.highlight !== undefined) {\n setupHighlight(app, options.highlight)\n }\n}\n\nexport default {\n install,\n} satisfies { install: (app: App, options?: ComponentLibOptions) => void }\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["C_Code","C_Icon","C_Upload","C_Barcode","C_Captcha","C_Cascade","C_Guide","C_Progress","C_Steps","C_ActionBar","C_Theme","C_Language","C_Date","C_Editor","C_Markdown","C_Map","C_City","C_VtableGantt","C_Signature","C_SplitPane","C_CollapsePanel","C_Time","C_FormSearch","C_Tree","C_QRCode","C_ImageCropper","C_Draggable","C_WaterFall","C_FullCalendar","C_NotificationCenter","C_Cron","C_FormulaEditor","C_AntV","C_VideoPlayer","C_FilePreview","C_WorkFlow","C_Form","C_Table","C_GlobalSearch","C_Menu","C_Breadcrumb","C_TagsView"],"sources":["../src/plugins/highlight.ts","../src/index.ts"],"sourcesContent":["\r\n\r\nimport type { App } from 'vue'\r\nimport type { HLJSApi, LanguageFn } from 'highlight.js'\r\nimport hljs from 'highlight.js/lib/core'\r\n\r\n// 导入默认主题样式\r\nimport 'highlight.js/styles/github.css'\r\n\r\n// 默认支持的语言包(常用语言预加载)\r\nimport javascript from 'highlight.js/lib/languages/javascript'\r\nimport typescript from 'highlight.js/lib/languages/typescript'\r\nimport json from 'highlight.js/lib/languages/json'\r\nimport xml from 'highlight.js/lib/languages/xml' // HTML\r\nimport css from 'highlight.js/lib/languages/css'\r\nimport bash from 'highlight.js/lib/languages/bash'\r\nimport yaml from 'highlight.js/lib/languages/yaml'\r\nimport markdown from 'highlight.js/lib/languages/markdown'\r\nimport java from 'highlight.js/lib/languages/java'\r\nimport csharp from 'highlight.js/lib/languages/csharp'\r\nimport go from 'highlight.js/lib/languages/go'\r\nimport python from 'highlight.js/lib/languages/python'\r\n\r\n// 可选语言包映射(懒加载)\r\nconst OPTIONAL_LANGUAGES: Record<\r\n string,\r\n () => Promise<{ default: LanguageFn }>\r\n> = {\r\n cpp: () => import('highlight.js/lib/languages/cpp'),\r\n c: () => import('highlight.js/lib/languages/c'),\r\n php: () => import('highlight.js/lib/languages/php'),\r\n ruby: () => import('highlight.js/lib/languages/ruby'),\r\n rust: () => import('highlight.js/lib/languages/rust'),\r\n swift: () => import('highlight.js/lib/languages/swift'),\r\n kotlin: () => import('highlight.js/lib/languages/kotlin'),\r\n scss: () => import('highlight.js/lib/languages/scss'),\r\n less: () => import('highlight.js/lib/languages/less'),\r\n sql: () => import('highlight.js/lib/languages/sql'),\r\n dockerfile: () => import('highlight.js/lib/languages/dockerfile'),\r\n powershell: () => import('highlight.js/lib/languages/powershell'),\r\n}\r\n\r\n// 插件配置选项\r\nexport interface HighlightPluginOptions {\r\n autoDetect?: boolean\r\n extraLanguages?: string[]\r\n}\r\n\r\n// 状态管理\r\nconst loadedLanguages = new Set<string>()\r\nconst hlJsInstance: HLJSApi = hljs\r\n\r\n/**\r\n * * @description 注册语言包到 highlight.js 实例\r\n * ? @param name - 语言名称\r\n * ? @param languageFn - 语言定义函数\r\n * ! @return void\r\n */\r\nfunction registerLanguage(name: string, languageFn: LanguageFn): void {\r\n hlJsInstance.registerLanguage(name, languageFn)\r\n loadedLanguages.add(name)\r\n}\r\n\r\n/**\r\n * * @description 初始化核心配置,注册默认语言包\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nfunction initializeCore(options: HighlightPluginOptions): void {\r\n // 注册默认语言包\r\n const defaultLanguages = [\r\n ['javascript', javascript],\r\n ['typescript', typescript],\r\n ['json', json],\r\n ['html', xml],\r\n ['xml', xml],\r\n ['css', css],\r\n ['bash', bash],\r\n ['shell', bash],\r\n ['yaml', yaml],\r\n ['yml', yaml],\r\n ['markdown', markdown],\r\n ['java', java],\r\n ['csharp', csharp],\r\n ['go', go],\r\n ['python', python],\r\n ] as const\r\n\r\n defaultLanguages.forEach(([name, langFn]) => {\r\n registerLanguage(name, langFn)\r\n })\r\n\r\n // 配置 highlight.js\r\n hlJsInstance.configure({\r\n ignoreUnescapedHTML: true,\r\n languages: options.autoDetect ? undefined : [],\r\n })\r\n\r\n // 预加载额外语言\r\n if (options.extraLanguages?.length) {\r\n loadLanguages(options.extraLanguages)\r\n }\r\n}\r\n\r\n/**\r\n * * @description 批量加载多个语言包\r\n * ? @param languages - 要加载的语言名称数组\r\n * ! @return Promise<string[]> 成功加载的语言名称数组\r\n */\r\nasync function loadLanguages(languages: string[]): Promise<string[]> {\r\n const loadPromises = languages.map(lang => loadLanguage(lang))\r\n const results = await Promise.allSettled(loadPromises)\r\n\r\n return results\r\n .map((result, index) =>\r\n result.status === 'fulfilled' ? languages[index] : null\r\n )\r\n .filter(Boolean) as string[]\r\n}\r\n\r\n/**\r\n * * @description 动态加载单个语言包\r\n * ? @param language - 要加载的语言名称\r\n * ! @return Promise<boolean> 是否加载成功\r\n */\r\nasync function loadLanguage(language: string): Promise<boolean> {\r\n if (loadedLanguages.has(language)) {\r\n return true\r\n }\r\n\r\n const loader = OPTIONAL_LANGUAGES[language.toLowerCase()]\r\n if (!loader) {\r\n console.warn(`[HighlightPlugin] Language '${language}' not supported`)\r\n return false\r\n }\r\n\r\n try {\r\n const languageModule = await loader()\r\n registerLanguage(language, languageModule.default)\r\n console.log(`[HighlightPlugin] Language '${language}' loaded successfully`)\r\n return true\r\n } catch (error) {\r\n console.error(\r\n `[HighlightPlugin] Failed to load language '${language}':`,\r\n error\r\n )\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * * @description 获取 highlight 功能的 API 接口\r\n * ! @return highlight API 对象,包含所有可用方法\r\n */\r\nexport const useHighlight = () => {\r\n return {\r\n // 核心方法\r\n getHljs: () => hlJsInstance,\r\n\r\n // 语言管理\r\n loadLanguage: (language: string) => loadLanguage(language),\r\n loadLanguages: (languages: string[]) => loadLanguages(languages),\r\n getLoadedLanguages: () => Array.from(loadedLanguages),\r\n }\r\n}\r\n\r\n/**\r\n * * @description 安装 highlight.js 插件到 Vue 应用\r\n * ? @param app - Vue 应用实例\r\n * ? @param options - 插件配置选项\r\n * ! @return void\r\n */\r\nexport function setupHighlight(app: App, options: HighlightPluginOptions = {}) {\r\n const pluginOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n ...options,\r\n }\r\n\r\n // 初始化核心配置\r\n initializeCore(pluginOptions)\r\n\r\n // 挂载到全局\r\n if (typeof window !== 'undefined') {\r\n window.hljs = hlJsInstance\r\n }\r\n\r\n // 提供给 Vue 应用\r\n const highlightAPI = useHighlight()\r\n app.provide('highlightManager', highlightAPI)\r\n app.config.globalProperties.$highlight = highlightAPI\r\n\r\n console.log('[HighlightPlugin] 🎨 highlight.js plugin installed successfully')\r\n}\r\n\r\n// 导出默认配置\r\nexport const defaultHighlightOptions: HighlightPluginOptions = {\r\n autoDetect: false,\r\n extraLanguages: [],\r\n}\r\n\r\n// 类型声明\r\ndeclare global {\r\n interface Window {\r\n hljs: HLJSApi\r\n }\r\n}\r\n","import type { App, Component } from 'vue'\r\n\r\n// ====== 全局样式由 sass CLI 编译到 dist/style.css,不再通过 JS 导入 ======\r\n\r\n// ====== 组件导入(仅用于 install 全量注册) ======\r\nimport { C_Code } from './components/C_Code'\r\nimport { C_Icon } from './components/C_Icon'\r\nimport { C_Upload } from './components/C_Upload'\r\nimport { C_Barcode } from './components/C_Barcode'\r\nimport { C_Captcha } from './components/C_Captcha'\r\nimport { C_Cascade } from './components/C_Cascade'\r\nimport { C_Guide } from './components/C_Guide'\r\nimport { C_Progress } from './components/C_Progress'\r\nimport { C_Steps } from './components/C_Steps'\r\nimport { C_ActionBar } from './components/C_ActionBar'\r\nimport { C_Theme } from './components/C_Theme'\r\nimport { C_Language } from './components/C_Language'\r\nimport { C_Date } from './components/C_Date'\r\nimport { C_Editor } from './components/C_Editor'\r\nimport { C_Markdown } from './components/C_Markdown'\r\nimport { C_Map } from './components/C_Map'\r\nimport { C_City } from './components/C_City'\r\nimport { C_VtableGantt } from './components/C_VtableGantt'\r\nimport { C_Signature } from './components/C_Signature'\r\nimport { C_SplitPane } from './components/C_SplitPane'\r\nimport { C_CollapsePanel } from './components/C_CollapsePanel'\r\nimport { C_Time } from './components/C_Time'\r\nimport { C_FormSearch } from './components/C_FormSearch'\r\nimport { C_Tree } from './components/C_Tree'\r\nimport { C_QRCode } from './components/C_QRCode'\r\nimport { C_ImageCropper } from './components/C_ImageCropper'\r\nimport { C_Draggable } from './components/C_Draggable'\r\nimport { C_WaterFall } from './components/C_WaterFall'\r\nimport { C_FullCalendar } from './components/C_FullCalendar'\r\nimport { C_NotificationCenter } from './components/C_NotificationCenter'\r\nimport { C_Cron } from './components/C_Cron'\r\nimport { C_FormulaEditor } from './components/C_FormulaEditor'\r\nimport { C_AntV } from './components/C_AntV'\r\nimport { C_VideoPlayer } from './components/C_VideoPlayer'\r\nimport { C_FilePreview } from './components/C_FilePreview'\r\nimport { C_WorkFlow } from './components/C_WorkFlow'\r\nimport { C_Form } from './components/C_Form'\r\nimport { C_Table } from './components/C_Table'\r\nimport { C_GlobalSearch } from './components/C_GlobalSearch'\r\nimport { C_Menu } from './components/C_Menu'\r\nimport { C_Breadcrumb } from './components/C_Breadcrumb'\r\nimport { C_TagsView } from './components/C_TagsView'\r\n\r\n// ====== 插件 ======\r\nimport { setupHighlight, useHighlight } from './plugins/highlight'\r\n\r\n// ====== 安装选项 ======\r\nexport interface ComponentLibOptions {\r\n highlight?: import('./plugins/highlight').HighlightPluginOptions\r\n}\r\n\r\n// ====== 组件列表(全量注册使用) ======\r\nconst components: Component[] = [\r\n C_Code,\r\n C_Icon,\r\n C_Upload,\r\n C_Barcode,\r\n C_Captcha,\r\n C_Cascade,\r\n C_Guide,\r\n C_Progress,\r\n C_Steps,\r\n C_ActionBar,\r\n C_Theme,\r\n C_Language,\r\n C_Date,\r\n C_Editor,\r\n C_Markdown,\r\n C_Map,\r\n C_City,\r\n C_VtableGantt,\r\n C_Signature,\r\n C_SplitPane,\r\n C_CollapsePanel,\r\n C_Time,\r\n C_FormSearch,\r\n C_Tree,\r\n C_QRCode,\r\n C_ImageCropper,\r\n C_Draggable,\r\n C_WaterFall,\r\n C_FullCalendar,\r\n C_NotificationCenter,\r\n C_Cron,\r\n C_FormulaEditor,\r\n C_AntV,\r\n C_VideoPlayer,\r\n C_FilePreview,\r\n C_WorkFlow,\r\n C_Form,\r\n C_Table,\r\n C_GlobalSearch,\r\n C_Menu,\r\n C_Breadcrumb,\r\n C_TagsView,\r\n]\r\n\r\n// ====== Barrel Re-exports:所有组件 + composables + types + constants ======\r\nexport * from './components/C_Code'\r\nexport * from './components/C_Icon'\r\nexport * from './components/C_Upload'\r\nexport * from './components/C_Barcode'\r\nexport * from './components/C_Captcha'\r\nexport * from './components/C_Cascade'\r\nexport * from './components/C_Guide'\r\nexport * from './components/C_Progress'\r\nexport * from './components/C_Steps'\r\nexport * from './components/C_ActionBar'\r\nexport * from './components/C_Theme'\r\nexport * from './components/C_Language'\r\nexport * from './components/C_Date'\r\nexport * from './components/C_Editor'\r\nexport * from './components/C_Markdown'\r\nexport * from './components/C_Map'\r\nexport * from './components/C_City'\r\nexport * from './components/C_VtableGantt'\r\nexport * from './components/C_Signature'\r\nexport * from './components/C_SplitPane'\r\nexport * from './components/C_CollapsePanel'\r\nexport * from './components/C_Time'\r\nexport * from './components/C_FormSearch'\r\nexport * from './components/C_Tree'\r\nexport * from './components/C_QRCode'\r\nexport * from './components/C_ImageCropper'\r\nexport * from './components/C_Draggable'\r\nexport * from './components/C_WaterFall'\r\nexport * from './components/C_FullCalendar'\r\nexport * from './components/C_NotificationCenter'\r\nexport * from './components/C_Cron'\r\nexport * from './components/C_FormulaEditor'\r\nexport * from './components/C_AntV'\r\nexport * from './components/C_VideoPlayer'\r\nexport * from './components/C_FilePreview'\r\nexport * from './components/C_WorkFlow'\r\nexport * from './components/C_Form'\r\nexport * from './components/C_Table'\r\nexport * from './components/C_GlobalSearch'\r\nexport * from './components/C_Menu'\r\nexport * from './components/C_Breadcrumb'\r\nexport * from './components/C_TagsView'\r\n\r\n// ====== 共享类型 + 适配器 ======\r\nexport * from './components/_shared'\r\n\r\n// ====== 工具函数(不属于任何组件的公共工具) ======\r\nexport { setItem, getItem, removeItem, removeAllItem } from './utils/storage'\r\n\r\n// ====== 插件导出 ======\r\nexport { setupHighlight, useHighlight }\r\nexport type { HighlightPluginOptions } from './plugins/highlight'\r\n\r\n// ====== 全量安装 ======\r\nconst install = (app: App, options: ComponentLibOptions = {}) => {\r\n components.forEach(component => {\r\n const name =\r\n (component as any).__name || (component as any).name || 'UnknownComponent'\r\n app.component(name, component)\r\n })\r\n\r\n if (options.highlight !== undefined) {\r\n setupHighlight(app, options.highlight)\r\n }\r\n}\r\n\r\nexport default {\r\n install,\r\n} satisfies { install: (app: App, options?: ComponentLibOptions) => void }\r\n"],"mappings":"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"}
@@ -50,13 +50,13 @@ declare const __VLS_export: vue.DefineComponent<IconProps, {
50
50
  onLoad?: (() => any) | undefined;
51
51
  }>, {
52
52
  type: "iconify" | "unocss" | "component" | "svg" | "image";
53
- size: number | string;
54
- rotate: number;
55
53
  name: string | any;
54
+ size: number | string;
55
+ title: string;
56
56
  color: string;
57
- loading: boolean;
57
+ rotate: number;
58
58
  flip: "horizontal" | "vertical" | "both";
59
- title: string;
59
+ loading: boolean;
60
60
  svgPath: string;
61
61
  viewBox: string;
62
62
  alt: string;
@@ -11,11 +11,11 @@ type __VLS_Props = {
11
11
  options?: LanguageOption[];
12
12
  };
13
13
  declare const __VLS_export: vue.DefineComponent<__VLS_Props, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
14
- "update:modelValue": (key: string) => any;
15
14
  change: (key: string) => any;
15
+ "update:modelValue": (key: string) => any;
16
16
  }, string, vue.PublicProps, Readonly<__VLS_Props> & Readonly<{
17
- "onUpdate:modelValue"?: ((key: string) => any) | undefined;
18
17
  onChange?: ((key: string) => any) | undefined;
18
+ "onUpdate:modelValue"?: ((key: string) => any) | undefined;
19
19
  }>, {
20
20
  modelValue: string;
21
21
  options: LanguageOption[];
@@ -38,8 +38,8 @@ declare const __VLS_export: vue.DefineComponent<Props, {
38
38
  insertText: (text: string) => void;
39
39
  wordCount: vue.ComputedRef<number>;
40
40
  }, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
41
- "update:modelValue": (value: string) => any;
42
41
  change: (text: string, html: string) => any;
42
+ "update:modelValue": (value: string) => any;
43
43
  save: (text: string, html: string) => any;
44
44
  "upload-image": (event: Event, insertImage: InsertImageFunction, files: FileList) => any;
45
45
  "fullscreen-change": (isFullscreen: boolean) => any;
@@ -48,8 +48,8 @@ declare const __VLS_export: vue.DefineComponent<Props, {
48
48
  "auto-save": (text: string) => any;
49
49
  "max-length-exceeded": (currentLength: number, maxLength: number) => any;
50
50
  }, string, vue.PublicProps, Readonly<Props> & Readonly<{
51
- "onUpdate:modelValue"?: ((value: string) => any) | undefined;
52
51
  onChange?: ((text: string, html: string) => any) | undefined;
52
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
53
53
  onSave?: ((text: string, html: string) => any) | undefined;
54
54
  "onUpload-image"?: ((event: Event, insertImage: InsertImageFunction, files: FileList) => any) | undefined;
55
55
  "onFullscreen-change"?: ((isFullscreen: boolean) => any) | undefined;
@@ -59,11 +59,11 @@ declare const __VLS_export: vue.DefineComponent<Props, {
59
59
  "onMax-length-exceeded"?: ((currentLength: number, maxLength: number) => any) | undefined;
60
60
  }>, {
61
61
  height: string | number;
62
- modelValue: string;
63
- placeholder: string;
64
62
  disabled: boolean;
65
- autoSave: boolean;
66
63
  mode: "edit" | "editable" | "preview";
64
+ placeholder: string;
65
+ modelValue: string;
66
+ autoSave: boolean;
67
67
  tocNavPosition: "left" | "right";
68
68
  defaultFullscreen: boolean;
69
69
  autofocus: boolean;
@@ -34,9 +34,9 @@ type __VLS_Slots = {} & {
34
34
  indicator?: (props: typeof __VLS_9) => any;
35
35
  };
36
36
  declare const __VLS_base: vue.DefineComponent<Props, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<Props> & Readonly<{}>, {
37
- status: "default" | "success" | "error" | "warning" | "info";
38
37
  strokeWidth: number;
39
38
  time: number;
39
+ status: "default" | "success" | "error" | "warning" | "info";
40
40
  percentage: number | number[];
41
41
  isAnimation: boolean;
42
42
  indicatorPlacement: "inside" | "outside";
@@ -76,10 +76,10 @@ declare const __VLS_export: vue.DefineComponent<__VLS_Props, {
76
76
  onClose?: ((fallbackPath: string) => any) | undefined;
77
77
  onCloseAll?: (() => any) | undefined;
78
78
  }>, {
79
- persistKey: string;
80
79
  homePath: string;
81
80
  homeTitle: string;
82
81
  homeIcon: string;
82
+ persistKey: string;
83
83
  contextMenuLabels: ContextMenuLabels;
84
84
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
85
85
  declare const _default: typeof __VLS_export;