@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.
- package/CHANGELOG.md +48 -32
- package/dist/C_Breadcrumb.js.map +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/C_Menu.js.map +1 -1
- package/dist/C_Menu2.js.map +1 -1
- package/dist/{C_Table-Dcam_tRs.css.map → C_Table-vZlcgH6x.css.map} +1 -1
- package/dist/{C_Table-tbUx-R4H.css.map → C_Table-wzAO43l0.css.map} +1 -1
- package/dist/C_Table.css +69 -69
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +1 -1
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-DX3LecK1.css.map → C_TagsView-BsutyC3U.css.map} +1 -1
- package/dist/{C_TagsView-DqOTa8bL.css.map → C_TagsView-Crm7yWg9.css.map} +1 -1
- package/dist/C_TagsView.css +36 -36
- package/dist/C_TagsView.js.map +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_TagsView2.js.map +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/constants2.d.ts +5 -5
- package/dist/constants3.d.ts +2 -2
- package/dist/constants4.d.ts +6 -6
- package/dist/constants5.d.ts +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index11.vue.d.ts +4 -4
- package/dist/index12.vue.d.ts +2 -2
- package/dist/index13.vue.d.ts +5 -5
- package/dist/index15.vue.d.ts +1 -1
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index19.vue.d.ts +3 -3
- package/dist/index2.vue.d.ts +1 -1
- package/dist/index4.vue.d.ts +4 -4
- package/dist/index5.vue.d.ts +2 -2
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index7.vue.d.ts +1 -1
- package/dist/index8.vue.d.ts +1 -1
- package/dist/index9.vue.d.ts +3 -3
- package/dist/menuAdapter.js +1 -1
- package/dist/menuAdapter.js.map +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +107 -107
- package/dist/useCollapsePanel.d.ts +3 -3
- package/dist/useCropperCore.d.ts +7 -7
- package/dist/useDraggableLayout.d.ts +2 -2
- package/dist/useDynamicFormState.d.ts +118 -118
- package/dist/useEdgeInteraction.d.ts +1 -1
- package/dist/useInfiniteScroll.d.ts +2 -2
- package/dist/useModalEdit.d.ts +0 -1
- package/dist/useQRCode.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +1 -1
- package/dist/useSplitResize.d.ts +2 -2
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +3 -3
- package/dist/useWorkflowValidation.d.ts +3 -3
- package/package.json +1 -1
package/dist/C_TagsView2.js.map
CHANGED
|
@@ -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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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -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;
|
package/dist/constants2.d.ts
CHANGED
|
@@ -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
|
-
|
|
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>;
|
package/dist/constants3.d.ts
CHANGED
|
@@ -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;
|
package/dist/constants4.d.ts
CHANGED
|
@@ -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;
|
package/dist/constants5.d.ts
CHANGED
|
@@ -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;
|
package/dist/index.cjs.map
CHANGED
|
@@ -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":"+oEAwBA,MAAM,GAGF,CACF,QAAW,OAAO,kCAClB,MAAS,OAAO,gCAChB,QAAW,OAAO,kCAClB,SAAY,OAAO,mCACnB,SAAY,OAAO,mCACnB,UAAa,OAAO,oCACpB,WAAc,OAAO,qCACrB,SAAY,OAAO,mCACnB,SAAY,OAAO,mCACnB,QAAW,OAAO,kCAClB,eAAkB,OAAO,yCACzB,eAAkB,OAAO,yCAC1B,CASK,EAAkB,IAAI,IACtB,EAAwBA,EAAAA,QAQ9B,SAAS,GAAiB,EAAc,EAA8B,CACpE,EAAa,iBAAiB,EAAM,EAAW,CAC/C,EAAgB,IAAI,EAAK,CAQ3B,SAAS,GAAe,EAAuC,CAEpC,CACvB,CAAC,aAAcC,EAAAA,QAAW,CAC1B,CAAC,aAAcC,EAAAA,QAAW,CAC1B,CAAC,OAAQC,EAAAA,QAAK,CACd,CAAC,OAAQC,EAAAA,QAAI,CACb,CAAC,MAAOA,EAAAA,QAAI,CACZ,CAAC,MAAOC,EAAAA,QAAI,CACZ,CAAC,OAAQC,EAAAA,QAAK,CACd,CAAC,QAASA,EAAAA,QAAK,CACf,CAAC,OAAQC,EAAAA,QAAK,CACd,CAAC,MAAOA,EAAAA,QAAK,CACb,CAAC,WAAYC,EAAAA,QAAS,CACtB,CAAC,OAAQC,EAAAA,QAAK,CACd,CAAC,SAAUC,EAAAA,QAAO,CAClB,CAAC,KAAMC,EAAAA,QAAG,CACV,CAAC,SAAUC,EAAAA,QAAO,CACnB,CAEgB,SAAS,CAAC,EAAM,KAAY,CAC3C,GAAiB,EAAM,EAAO,EAC9B,CAGF,EAAa,UAAU,CACrB,oBAAqB,GACrB,UAAW,EAAQ,WAAa,IAAA,GAAY,EAAE,CAC/C,CAAC,CAGE,EAAQ,gBAAgB,QAC1B,GAAc,EAAQ,eAAe,CASzC,eAAe,GAAc,EAAwC,CACnE,IAAM,EAAe,EAAU,IAAI,GAAQ,GAAa,EAAK,CAAC,CAG9D,OAFgB,MAAM,QAAQ,WAAW,EAAa,EAGnD,KAAK,EAAQ,IACZ,EAAO,SAAW,YAAc,EAAU,GAAS,KACpD,CACA,OAAO,QAAQ,CAQpB,eAAe,GAAa,EAAoC,CAC9D,GAAI,EAAgB,IAAI,EAAS,CAC/B,MAAO,GAGT,IAAM,EAAS,GAAmB,EAAS,aAAa,EACxD,GAAI,CAAC,EAEH,OADA,QAAQ,KAAK,+BAA+B,EAAS,iBAAiB,CAC/D,GAGT,GAAI,CAIF,OAFA,GAAiB,GADM,MAAM,GAAQ,EACK,QAAQ,CAClD,QAAQ,IAAI,+BAA+B,EAAS,uBAAuB,CACpE,SACA,EAAO,CAKd,OAJA,QAAQ,MACN,8CAA8C,EAAS,IACvD,EACD,CACM,IAQX,MAAa,QACJ,CAEL,YAAe,EAGf,aAAe,GAAqB,GAAa,EAAS,CAC1D,cAAgB,GAAwB,GAAc,EAAU,CAChE,uBAA0B,MAAM,KAAK,EAAgB,CACtD,EASH,SAAgB,GAAe,EAAU,EAAkC,EAAE,CAAE,CAQ7E,GAP8C,CAC5C,WAAY,GACZ,eAAgB,EAAE,CAClB,GAAG,EACJ,CAG4B,CAGzB,OAAO,OAAW,MACpB,OAAO,KAAO,GAIhB,IAAM,EAAe,IAAc,CACnC,EAAI,QAAQ,mBAAoB,EAAa,CAC7C,EAAI,OAAO,iBAAiB,WAAa,EAEzC,QAAQ,IAAI,kEAAkE,CCvIhF,MAAM,GAA0B,CAC9BC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,GAAAA,EACAC,EAAAA,EACAC,GAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,GAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,EAAAA,EACAC,GAAAA,EACAC,GAAAA,EACAC,EAAAA,EACD,CAqED,IAAA,GAAe,CACb,SAbe,EAAU,EAA+B,EAAE,GAAK,CAC/D,GAAW,QAAQ,GAAa,CAC9B,IAAM,EACH,EAAkB,QAAW,EAAkB,MAAQ,mBAC1D,EAAI,UAAU,EAAM,EAAU,EAC9B,CAEE,EAAQ,YAAc,IAAA,IACxB,GAAe,EAAK,EAAQ,UAAU,EAMzC"}
|
|
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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"}
|
package/dist/index11.vue.d.ts
CHANGED
|
@@ -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
|
-
|
|
57
|
+
rotate: number;
|
|
58
58
|
flip: "horizontal" | "vertical" | "both";
|
|
59
|
-
|
|
59
|
+
loading: boolean;
|
|
60
60
|
svgPath: string;
|
|
61
61
|
viewBox: string;
|
|
62
62
|
alt: string;
|
package/dist/index12.vue.d.ts
CHANGED
|
@@ -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[];
|
package/dist/index13.vue.d.ts
CHANGED
|
@@ -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;
|
package/dist/index15.vue.d.ts
CHANGED
|
@@ -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";
|
package/dist/index17.vue.d.ts
CHANGED
|
@@ -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;
|