UNPKG

@opensig/opendesign

Version:

<p align="center"><img src="../docs/public/opendesign-logo-light.png"/></p> <h1 align="center">opendesign</h1> <p align="center">一个 Vue 3 组件库</p> <p align="center"><b>皮肤可定制,使用 TypeScript</b></p>

303 lines (302 loc) 10.6 kB
import { defineComponent, ref, computed, watch, provide, createElementBlock, openBlock, normalizeClass, unref, createElementVNode, withDirectives, createCommentVNode, renderSlot, createVNode, normalizeStyle, nextTick } from "vue"; import { tabInjectKey } from "./provide.mjs"; import { IconChevronLeft, IconChevronRight, IconAdd } from "../_utils/icons.mjs"; import { tabProps } from "./types.mjs"; import { useScreen } from "../hooks/use-screen.mjs"; import { vOnResize } from "../directives/on-resize.mjs"; import { debounceRAF } from "../_utils/helper.mjs"; import { defaultSize } from "../_utils/global.mjs"; const _hoisted_1 = { key: 0, class: "o-tab-head-prefix" }; const _hoisted_2 = { class: "o-tab-navs" }; const _hoisted_3 = { key: 1, class: "o-tab-head-suffix" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "OTab", props: tabProps, emits: ["update:modelValue", "change", "delete", "add"], setup(__props, { emit: __emit }) { const props = __props; const emits = __emit; const { isPhonePad } = useScreen(); const activeKey = ref(props.modelValue); const anchorStyle = ref({}); const navWrapRef = ref(null); const navsRef = ref(null); const bodyRef = ref(null); const valueSet = []; let activeNavEl = null; const isScroll = ref(false); const prevDisabled = ref(true); const nextDisabled = ref(true); const showArrow = computed(() => { return !isPhonePad.value && isScroll.value; }); const scrollActiveNavIntoView = () => { var _a; if (isScroll.value && activeNavEl && navWrapRef.value) { const { offsetLeft } = activeNavEl; const { scrollLeft, clientWidth } = navWrapRef.value; const center = scrollLeft + clientWidth / 2; if (offsetLeft > center || offsetLeft < center) { (_a = navWrapRef.value) == null ? void 0 : _a.scrollTo({ left: offsetLeft - clientWidth / 2, behavior: "smooth" }); } } }; const onWrapScroll = debounceRAF(() => { if (navWrapRef.value) { const { scrollLeft, scrollWidth, clientWidth } = navWrapRef.value; prevDisabled.value = scrollLeft === 0; nextDisabled.value = scrollLeft + 1 >= scrollWidth - clientWidth; } }); const updateNavScroll = () => { if (navWrapRef.value && navsRef.value) { const { clientWidth: wrapWidth } = navWrapRef.value; const { clientWidth: width } = navsRef.value; isScroll.value = wrapWidth < width; if (isScroll.value) { nextTick(() => { onWrapScroll(); scrollActiveNavIntoView(); }); } } }; watch( () => props.modelValue, (v) => { activeKey.value = v; } ); const updateAnchor = () => { if (!activeNavEl) { return; } const { clientWidth, offsetLeft } = activeNavEl; anchorStyle.value = { transform: `translate3d(${offsetLeft}px, 0px, 0px)`, width: `${clientWidth}px` }; }; watch(() => isScroll.value, updateAnchor); const updateValue = (value, navEl) => { emits("update:modelValue", value); activeNavEl = navEl; if (activeKey.value !== value) { emits("change", value, activeKey.value); activeKey.value = value; } if (navEl) { activeNavEl = navEl; updateAnchor(); scrollActiveNavIntoView(); } }; const isAdding = ref(false); const initValue = (value, navEl) => { if (!valueSet.includes(value)) { valueSet.push(value); } if (activeKey.value === void 0 || isAdding.value) { updateValue(value, navEl); isAdding.value = false; } if (activeKey.value === value && navEl) { activeNavEl = navEl; updateAnchor(); } }; const onDeletePane = (value) => { emits("delete", value); const idx = valueSet.indexOf(value); if (activeKey.value === value) { activeKey.value = valueSet[idx > 0 ? idx - 1 : 0]; emits("change", activeKey.value, value); } valueSet.splice(idx, 1); }; const onAddNav = (e) => { emits("add", e); if (!props.addInactive) { isAdding.value = true; } }; provide(tabInjectKey, { lazy: props.lazy, navsRef, bodyRef, activeValue: activeKey, updateValue, onDeletePane, initValue }); const onHeadResize = debounceRAF(() => { updateAnchor(); updateNavScroll(); scrollActiveNavIntoView(); }); const navScroll = (to) => { if (!navWrapRef.value) { return; } const { clientWidth } = navWrapRef.value; const i = to === "prev" ? -1 : to === "next" ? 1 : 0; navWrapRef.value.scrollBy({ left: i * clientWidth, behavior: "smooth" }); }; return (_ctx, _cache) => { return openBlock(), createElementBlock( "div", { class: normalizeClass(["o-tab", [`o-tab-${props.variant}`, `o-tab-${props.size || unref(defaultSize)}`]]) }, [ createElementVNode( "div", { class: normalizeClass(["o-tab-head", [ { "with-act": _ctx.$slots.suffix || _ctx.$slots.prefix, "show-line": props.line }, props.headerClass ]]) }, [ _ctx.$slots.prefix ? withDirectives((openBlock(), createElementBlock("div", _hoisted_1, [ renderSlot(_ctx.$slots, "prefix") ])), [ [unref(vOnResize), unref(onHeadResize)] ]) : createCommentVNode("v-if", true), createElementVNode("div", _hoisted_2, [ createElementVNode( "div", { class: normalizeClass([{ "o-tab-navs-scrollable": isScroll.value }, "o-tab-navs-container"]) }, [ showArrow.value ? (openBlock(), createElementBlock( "div", { key: 0, class: normalizeClass(["o-tab-nav-btn prev", { "o-tab-nav-btn-disabled": prevDisabled.value }]), onClick: _cache[0] || (_cache[0] = ($event) => navScroll("prev")) }, [ createVNode(unref(IconChevronLeft)) ], 2 /* CLASS */ )) : createCommentVNode("v-if", true), createElementVNode( "div", { ref_key: "navWrapRef", ref: navWrapRef, class: "o-tab-navs-wrap o-hide-scrollbar", onScrollPassive: _cache[1] || (_cache[1] = //@ts-ignore (...args) => unref(onWrapScroll) && unref(onWrapScroll)(...args)) }, [ withDirectives(createElementVNode( "div", { class: "o-tab-nav-list", ref_key: "navsRef", ref: navsRef }, null, 512 /* NEED_PATCH */ ), [ [unref(vOnResize), unref(onHeadResize)] ]), props.variant === "text" ? (openBlock(), createElementBlock( "div", { key: 0, class: "o-tab-nav-anchor", style: normalizeStyle(anchorStyle.value) }, [ renderSlot(_ctx.$slots, "anchor", {}, () => [ _cache[3] || (_cache[3] = createElementVNode( "div", { class: "o-tab-nav-anchor-line" }, null, -1 /* HOISTED */ )) ]) ], 4 /* STYLE */ )) : createCommentVNode("v-if", true) ], 544 /* NEED_HYDRATION, NEED_PATCH */ ), showArrow.value ? (openBlock(), createElementBlock( "div", { key: 1, class: normalizeClass(["o-tab-nav-btn next", { "o-tab-nav-btn-disabled": nextDisabled.value }]), onClick: _cache[2] || (_cache[2] = ($event) => navScroll("next")) }, [ createVNode(unref(IconChevronRight)) ], 2 /* CLASS */ )) : createCommentVNode("v-if", true) ], 2 /* CLASS */ ), props.addable ? (openBlock(), createElementBlock("div", { key: 0, class: "o-tab-nav-add", onClick: onAddNav }, [ createVNode(unref(IconAdd)) ])) : createCommentVNode("v-if", true) ]), _ctx.$slots.suffix ? withDirectives((openBlock(), createElementBlock("div", _hoisted_3, [ renderSlot(_ctx.$slots, "suffix") ])), [ [unref(vOnResize), unref(onHeadResize)] ]) : createCommentVNode("v-if", true) ], 2 /* CLASS */ ), createElementVNode( "div", { ref_key: "bodyRef", ref: bodyRef, class: "o-tab-body" }, [ renderSlot(_ctx.$slots, "default") ], 512 /* NEED_PATCH */ ) ], 2 /* CLASS */ ); }; } }); export { _sfc_main as default };