UNPKG

@extclp/vexip-ui

Version:

A Vue 3 UI library, Highly customizability, full TypeScript, performance pretty good

1 lines 10.5 kB
{"version":3,"file":"tab-nav.vue2.mjs","sources":["../../../components/tab-nav/tab-nav.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { Icon } from '@/components/icon'\nimport { Renderer } from '@/components/renderer'\nimport { ResizeObserver } from '@/components/resize-observer'\nimport { Scroll } from '@/components/scroll'\nimport { TabNavItem } from '@/components/tab-nav-item'\n\nimport { computed, onMounted, provide, reactive, ref, toRef, watch } from 'vue'\n\nimport { emitEvent, useIcons, useNameHelper, useProps } from '@vexip-ui/config'\nimport { useDisplay } from '@vexip-ui/hooks'\nimport { debounceMinor, isNull } from '@vexip-ui/utils'\nimport { tabNavProps } from './props'\nimport { TAB_NAV_STATE, trackStyleMap } from './symbol'\n\nimport type { ChangeEvent, ItemState, TabNavSlots } from './symbol'\n\ndefineOptions({ name: 'TabNav' })\n\nconst _props = defineProps(tabNavProps)\nconst props = useProps('tabNav', _props, {\n active: {\n default: null,\n static: true\n },\n card: false,\n options: {\n default: () => [],\n static: true\n },\n align: 'left',\n placement: 'top',\n closable: false,\n showAdd: false,\n slots: () => ({})\n})\n\nconst emit = defineEmits(['update:active'])\n\nconst slots = defineSlots<TabNavSlots>()\n\nconst nh = useNameHelper('tab-nav')\nconst icons = useIcons()\nconst currentActive = ref(props.active)\nconst markerPosition = ref(0)\nconst markerSize = ref(0)\nconst itemStates = new Set<ItemState>()\n\nconst wrapper = useDisplay(updateMarkerPosition)\nconst scroll = ref<InstanceType<typeof Scroll>>()\n\nconst className = computed(() => {\n return {\n [nh.b()]: true,\n [nh.bs('vars')]: true,\n [nh.bm('inherit')]: props.inherit,\n [nh.bm(`align-${props.align}`)]: true,\n [nh.bm(props.placement)]: true,\n [nh.bm('card')]: props.card\n }\n})\nconst markerStyle = computed(() => {\n const [position, length] = trackStyleMap[props.placement]\n\n return {\n [position]: `${markerPosition.value}px`,\n [length]: `${markerSize.value}px`\n }\n})\nconst items = computed(() => {\n return props.options.map(item => {\n if (typeof item === 'string' || typeof item === 'number') {\n return { label: item }\n }\n\n return item\n })\n})\nconst scrollMode = computed(() => {\n return props.placement === 'top' || props.placement === 'bottom' ? 'horizontal-exact' : 'vertical'\n})\n\nconst refreshLabels = debounceMinor(() => {\n const total = itemStates.size\n\n Array.from(itemStates).forEach((item, index) => {\n item.index = index + 1\n item.total = total\n\n if (isNull(item.label)) {\n item.label = index + 1\n }\n })\n\n if (itemStates.size >= 1 && isActiveEmpty()) {\n currentActive.value = Array.from(itemStates)[0].label\n }\n})\n\nprovide(\n TAB_NAV_STATE,\n reactive({\n currentActive,\n closable: toRef(props, 'closable'),\n increaseItem,\n decreaseItem,\n handleActive,\n handleClose,\n refreshLabels\n })\n)\n\nwatch(\n () => props.active,\n value => {\n currentActive.value = value\n updateMarkerPosition()\n }\n)\nwatch(\n () => props.placement,\n () => {\n requestAnimationFrame(updateMarkerPosition)\n }\n)\n\nonMounted(updateMarkerPosition)\n\ndefineExpose({\n items,\n wrapper,\n scroll,\n updateMarkerPosition,\n handleAdd\n})\n\nfunction isActiveEmpty() {\n return isNull(currentActive.value) || currentActive.value === ''\n}\n\nfunction increaseItem(item: ItemState) {\n itemStates.add(item)\n refreshLabels()\n}\n\nfunction decreaseItem(item: ItemState) {\n itemStates.delete(item)\n refreshLabels()\n}\n\nfunction handleActive(label: string | number) {\n currentActive.value = label\n\n updateMarkerPosition()\n emit('update:active', label)\n emitEvent(props.onChange as ChangeEvent, label)\n}\n\nfunction handleAdd() {\n emitEvent(props.onAdd)\n}\n\nfunction handleClose(label: string | number) {\n emitEvent(props.onClose as ChangeEvent, label)\n\n requestAnimationFrame(updateMarkerPosition)\n}\n\nfunction updateMarkerPosition() {\n const activeItem = Array.from(itemStates).find(item => item.label === currentActive.value)\n\n if (activeItem?.el) {\n if (props.placement === 'top' || props.placement === 'bottom') {\n markerPosition.value = activeItem.el.offsetLeft\n markerSize.value = activeItem.el.offsetWidth\n } else {\n markerPosition.value = activeItem.el.offsetTop\n markerSize.value = activeItem.el.offsetHeight\n }\n } else {\n markerPosition.value = 0\n markerSize.value = 0\n }\n}\n</script>\n\n<template>\n <div ref=\"wrapper\" :class=\"className\" tabindex=\"-1\">\n <ResizeObserver :on-resize=\"updateMarkerPosition\">\n <div :class=\"[nh.be('extra'), nh.bem('extra', 'prefix')]\">\n <div v-if=\"slots.prefix || props.slots.prefix\" :class=\"nh.be('prefix')\">\n <slot name=\"prefix\">\n <Renderer :renderer=\"props.slots.prefix\"></Renderer>\n </slot>\n </div>\n </div>\n </ResizeObserver>\n <Scroll\n ref=\"scroll\"\n :class=\"nh.be('scroll')\"\n :mode=\"scrollMode\"\n :delta-x=\"40\"\n :delta-y=\"40\"\n scroll-tag=\"ul\"\n :scroll-class=\"nh.be('list')\"\n :scroll-attrs=\"{ role: 'tablist' }\"\n >\n <slot>\n <TabNavItem\n v-for=\"item in items\"\n :key=\"item.label\"\n :label=\"item.label\"\n :icon=\"item.icon\"\n :disabled=\"item.disabled\"\n :closable=\"item.closable\"\n @toggle=\"item.onToggle\"\n >\n {{ item.content || item.label }}\n </TabNavItem>\n </slot>\n <li v-if=\"props.showAdd || slots.add || props.slots.add\" :class=\"nh.be('item')\" role=\"none\">\n <div :class=\"nh.be('pad')\"></div>\n <button type=\"button\" :class=\"nh.be('add')\" @click=\"handleAdd\">\n <slot name=\"add\">\n <Renderer :renderer=\"props.slots.add\">\n <Icon v-bind=\"icons.plus\" :scale=\"+(icons.plus.scale || 1) * 1.2\"></Icon>\n </Renderer>\n </slot>\n </button>\n </li>\n <div\n v-if=\"!props.card\"\n :class=\"nh.be('track')\"\n role=\"none\"\n :style=\"markerStyle\"\n >\n <slot name=\"marker\">\n <Renderer :renderer=\"props.slots.marker\">\n <div :class=\"nh.be('marker')\"></div>\n </Renderer>\n </slot>\n </div>\n </Scroll>\n <ResizeObserver :on-resize=\"updateMarkerPosition\">\n <div :class=\"[nh.be('extra'), nh.bem('extra', 'suffix')]\">\n <div v-if=\"slots.suffix || props.slots.suffix\" :class=\"nh.be('suffix')\">\n <slot name=\"suffix\">\n <Renderer :renderer=\"props.slots.suffix\"></Renderer>\n </slot>\n </div>\n </div>\n </ResizeObserver>\n </div>\n</template>\n"],"names":["props","useProps","__props","emit","__emit","slots","_useSlots","nh","useNameHelper","icons","useIcons","currentActive","ref","markerPosition","markerSize","itemStates","wrapper","useDisplay","updateMarkerPosition","scroll","className","computed","markerStyle","position","length","trackStyleMap","items","item","scrollMode","refreshLabels","debounceMinor","total","index","isNull","isActiveEmpty","provide","TAB_NAV_STATE","reactive","toRef","increaseItem","decreaseItem","handleActive","handleClose","watch","value","onMounted","__expose","handleAdd","label","emitEvent","activeItem"],"mappings":"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"}