element-plus
Version:
A Component Library for Vue 3
328 lines (327 loc) • 13.5 kB
JavaScript
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
require("../../../../_virtual/_rolldown/runtime.js");
const require_types = require("../../../../utils/types.js");
const require_numbers = require("../../../../utils/numbers.js");
const require_index = require("../../../../hooks/use-namespace/index.js");
const require_use_cache = require("../hooks/use-cache.js");
const require_defaults = require("../defaults.js");
const require_use_wheel = require("../hooks/use-wheel.js");
const require_props = require("../props.js");
const require_utils = require("../utils.js");
const require_scrollbar = require("../components/scrollbar.js");
let _vueuse_core = require("@vueuse/core");
let vue = require("vue");
let _vue_shared = require("@vue/shared");
//#region ../../packages/components/virtual-list/src/builders/build-list.ts
const createList = ({ name, getOffset, getItemSize, getItemOffset, getEstimatedTotalSize, getStartIndexForOffset, getStopIndexForStartIndex, initCache, clearCache, validateProps }) => {
return (0, vue.defineComponent)({
name: name ?? "ElVirtualList",
props: require_props.virtualizedListProps,
emits: [
require_defaults.ITEM_RENDER_EVT,
require_defaults.SCROLL_EVT,
require_defaults.END_REACHED_EVT
],
setup(props, { emit, expose }) {
validateProps(props);
const instance = (0, vue.getCurrentInstance)();
const ns = require_index.useNamespace("vl");
const dynamicSizeCache = (0, vue.ref)(initCache(props, instance));
const getItemStyleCache = require_use_cache.useCache();
const windowRef = (0, vue.ref)();
const innerRef = (0, vue.ref)();
const scrollbarRef = (0, vue.ref)();
const states = (0, vue.ref)({
isScrolling: false,
scrollDir: require_defaults.FORWARD,
scrollOffset: require_types.isNumber(props.initScrollOffset) ? props.initScrollOffset : 0,
updateRequested: false,
isScrollbarDragging: false
});
const itemsToRender = (0, vue.computed)(() => {
const { total, cache } = props;
const { isScrolling, scrollDir, scrollOffset } = (0, vue.unref)(states);
if (total === 0) return [
0,
0,
0,
0
];
const startIndex = getStartIndexForOffset(props, scrollOffset, (0, vue.unref)(dynamicSizeCache));
const stopIndex = getStopIndexForStartIndex(props, startIndex, scrollOffset, (0, vue.unref)(dynamicSizeCache));
const cacheBackward = !isScrolling || scrollDir === "backward" ? Math.max(1, cache) : 1;
const cacheForward = !isScrolling || scrollDir === "forward" ? Math.max(1, cache) : 1;
return [
Math.max(0, startIndex - cacheBackward),
Math.max(0, Math.min(total - 1, stopIndex + cacheForward)),
startIndex,
stopIndex
];
});
const estimatedTotalSize = (0, vue.computed)(() => getEstimatedTotalSize(props, (0, vue.unref)(dynamicSizeCache)));
const _isHorizontal = (0, vue.computed)(() => require_utils.isHorizontal(props.layout));
const windowStyle = (0, vue.computed)(() => [
{
position: "relative",
[`overflow-${_isHorizontal.value ? "x" : "y"}`]: "scroll",
WebkitOverflowScrolling: "touch",
willChange: "transform"
},
{
direction: props.direction,
height: require_types.isNumber(props.height) ? `${props.height}px` : props.height,
width: require_types.isNumber(props.width) ? `${props.width}px` : props.width
},
props.style
]);
const innerStyle = (0, vue.computed)(() => {
const size = (0, vue.unref)(estimatedTotalSize);
const horizontal = (0, vue.unref)(_isHorizontal);
const innerWidth = props.innerWidth;
return {
height: horizontal ? "100%" : `${size}px`,
pointerEvents: (0, vue.unref)(states).isScrolling ? "none" : void 0,
width: horizontal ? `${size}px` : innerWidth !== void 0 ? require_types.isNumber(innerWidth) ? `${innerWidth}px` : innerWidth : "100%",
margin: 0,
boxSizing: "border-box"
};
});
const clientSize = (0, vue.computed)(() => _isHorizontal.value ? props.width : props.height);
const maxOffset = (0, vue.computed)(() => Math.max(0, estimatedTotalSize.value - clientSize.value));
const normalizeOffset = (offset) => (0, _vueuse_core.clamp)(offset, 0, maxOffset.value);
const EDGE_TOLERANCE = 1;
const getEdgeState = (normalizedOffset) => ({
start: !require_numbers.isGreaterThan(normalizedOffset, 0, EDGE_TOLERANCE),
end: !require_numbers.isGreaterThan(maxOffset.value, normalizedOffset, EDGE_TOLERANCE)
});
const normalizedScrollOffset = (0, vue.computed)(() => normalizeOffset(states.value.scrollOffset));
const currentEdgeState = (0, vue.computed)(() => getEdgeState(normalizedScrollOffset.value));
let edgeState = currentEdgeState.value;
const { onWheel } = require_use_wheel.default({
atStartEdge: (0, vue.computed)(() => currentEdgeState.value.start),
atEndEdge: (0, vue.computed)(() => currentEdgeState.value.end),
layout: (0, vue.computed)(() => props.layout)
}, (offset) => {
scrollbarRef.value.onMouseUp?.();
scrollTo(Math.min(states.value.scrollOffset + offset, maxOffset.value));
});
(0, _vueuse_core.useEventListener)(windowRef, "wheel", onWheel, { passive: false });
const emitEvents = () => {
const { total } = props;
if (total > 0) {
const [cacheStart, cacheEnd, visibleStart, visibleEnd] = (0, vue.unref)(itemsToRender);
emit(require_defaults.ITEM_RENDER_EVT, cacheStart, cacheEnd, visibleStart, visibleEnd);
}
const { scrollDir, scrollOffset, updateRequested } = (0, vue.unref)(states);
emit(require_defaults.SCROLL_EVT, scrollDir, scrollOffset, updateRequested);
};
const emitEndReached = (direction, offset) => {
const nextEdgeState = getEdgeState(offset);
const horizontalEnd = props.direction === "rtl" ? "left" : "right";
const horizontalStart = props.direction === "rtl" ? "right" : "left";
if (direction === "forward" && nextEdgeState.end && !edgeState.end) emit(require_defaults.END_REACHED_EVT, _isHorizontal.value ? horizontalEnd : "bottom");
if (direction === "backward" && nextEdgeState.start && !edgeState.start) emit(require_defaults.END_REACHED_EVT, _isHorizontal.value ? horizontalStart : "top");
edgeState = nextEdgeState;
};
const updateScrollOffset = (offset, { isScrolling, updateRequested }) => {
const currentState = (0, vue.unref)(states);
const nextOffset = Math.max(offset, 0);
if (nextOffset === currentState.scrollOffset) return;
const scrollDir = require_utils.getScrollDir(currentState.scrollOffset, nextOffset);
states.value = {
...currentState,
isScrolling,
scrollDir,
scrollOffset: nextOffset,
updateRequested
};
emitEndReached(scrollDir, normalizeOffset(nextOffset));
(0, vue.nextTick)(resetIsScrolling);
};
const scrollVertically = (e) => {
const { clientHeight, scrollHeight, scrollTop } = e.currentTarget;
if ((0, vue.unref)(states).scrollOffset === scrollTop) return;
updateScrollOffset(Math.min(scrollTop, scrollHeight - clientHeight), {
isScrolling: true,
updateRequested: false
});
};
const scrollHorizontally = (e) => {
const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget;
if ((0, vue.unref)(states).scrollOffset === scrollLeft) return;
const { direction } = props;
let scrollOffset = scrollLeft;
if (direction === "rtl") switch (require_utils.getRTLOffsetType()) {
case require_defaults.RTL_OFFSET_NAG:
scrollOffset = -scrollLeft;
break;
case require_defaults.RTL_OFFSET_POS_DESC:
scrollOffset = scrollWidth - clientWidth - scrollLeft;
break;
}
updateScrollOffset(Math.min(scrollOffset, scrollWidth - clientWidth), {
isScrolling: true,
updateRequested: false
});
};
const onScroll = (e) => {
(0, vue.unref)(_isHorizontal) ? scrollHorizontally(e) : scrollVertically(e);
emitEvents();
};
const onScrollbarScroll = (distanceToGo, totalSteps) => {
const offset = maxOffset.value / totalSteps * distanceToGo;
scrollTo(Math.min(maxOffset.value, offset));
};
const scrollTo = (offset) => {
updateScrollOffset(offset, {
isScrolling: (0, vue.unref)(states).isScrolling,
updateRequested: true
});
};
const scrollToItem = (idx, alignment = require_defaults.AUTO_ALIGNMENT) => {
const { scrollOffset } = (0, vue.unref)(states);
idx = Math.max(0, Math.min(idx, props.total - 1));
scrollTo(getOffset(props, idx, alignment, scrollOffset, (0, vue.unref)(dynamicSizeCache)));
};
const getItemStyle = (idx) => {
const { direction, itemSize, layout } = props;
const itemStyleCache = getItemStyleCache.value(clearCache && itemSize, clearCache && layout, clearCache && direction);
let style;
if ((0, _vue_shared.hasOwn)(itemStyleCache, String(idx))) style = itemStyleCache[idx];
else {
const offset = getItemOffset(props, idx, (0, vue.unref)(dynamicSizeCache));
const size = getItemSize(props, idx, (0, vue.unref)(dynamicSizeCache));
const horizontal = (0, vue.unref)(_isHorizontal);
const isRtl = direction === "rtl";
const offsetHorizontal = horizontal ? offset : 0;
itemStyleCache[idx] = style = {
position: "absolute",
left: isRtl ? void 0 : `${offsetHorizontal}px`,
right: isRtl ? `${offsetHorizontal}px` : void 0,
top: !horizontal ? `${offset}px` : 0,
height: !horizontal ? `${size}px` : "100%",
width: horizontal ? `${size}px` : "100%"
};
}
return style;
};
const resetIsScrolling = () => {
states.value.isScrolling = false;
(0, vue.nextTick)(() => {
getItemStyleCache.value(-1, null, null);
});
};
const resetScrollTop = () => {
const window = windowRef.value;
if (window) window.scrollTop = 0;
};
(0, vue.onMounted)(() => {
if (!_vueuse_core.isClient) return;
const { initScrollOffset } = props;
const windowElement = (0, vue.unref)(windowRef);
if (require_types.isNumber(initScrollOffset) && windowElement) if ((0, vue.unref)(_isHorizontal)) windowElement.scrollLeft = initScrollOffset;
else windowElement.scrollTop = initScrollOffset;
emitEvents();
});
(0, vue.onUpdated)(() => {
const { direction, layout } = props;
const { scrollOffset, updateRequested } = (0, vue.unref)(states);
const windowElement = (0, vue.unref)(windowRef);
if (updateRequested && windowElement) if (layout === "horizontal") if (direction === "rtl") switch (require_utils.getRTLOffsetType()) {
case require_defaults.RTL_OFFSET_NAG:
windowElement.scrollLeft = -scrollOffset;
break;
case require_defaults.RTL_OFFSET_POS_ASC:
windowElement.scrollLeft = scrollOffset;
break;
default: {
const { clientWidth, scrollWidth } = windowElement;
windowElement.scrollLeft = scrollWidth - clientWidth - scrollOffset;
break;
}
}
else windowElement.scrollLeft = scrollOffset;
else windowElement.scrollTop = scrollOffset;
});
(0, vue.onActivated)(() => {
(0, vue.unref)(windowRef).scrollTop = (0, vue.unref)(states).scrollOffset;
});
(0, vue.watch)(maxOffset, () => {
edgeState = currentEdgeState.value;
});
const api = {
ns,
clientSize,
estimatedTotalSize,
windowStyle,
windowRef,
innerRef,
innerStyle,
itemsToRender,
scrollbarRef,
states,
getItemStyle,
onScroll,
onScrollbarScroll,
onWheel,
scrollTo,
scrollToItem,
resetScrollTop
};
expose({
windowRef,
innerRef,
getItemStyleCache,
scrollTo,
scrollToItem,
resetScrollTop,
states
});
return api;
},
render(ctx) {
const { $slots, className, clientSize, containerElement, data, getItemStyle, innerElement, itemsToRender, innerStyle, layout, scrollbarAlwaysOn, total, onScroll, onScrollbarScroll, states, useIsScrolling, windowStyle, ns } = ctx;
const [start, end] = itemsToRender;
const Container = (0, vue.resolveDynamicComponent)(containerElement);
const Inner = (0, vue.resolveDynamicComponent)(innerElement);
const children = [];
if (total > 0) for (let i = start; i <= end; i++) children.push((0, vue.h)(vue.Fragment, { key: i }, $slots.default?.({
data,
index: i,
isScrolling: useIsScrolling ? states.isScrolling : void 0,
style: getItemStyle(i)
})));
const InnerNode = [(0, vue.h)(Inner, (0, vue.mergeProps)(ctx.innerProps, {
style: innerStyle,
ref: "innerRef"
}), !(0, _vue_shared.isString)(Inner) ? { default: () => children } : children)];
const scrollbar = (0, vue.h)(require_scrollbar.default, {
ref: "scrollbarRef",
clientSize,
layout,
onScroll: onScrollbarScroll,
ratio: clientSize * 100 / this.estimatedTotalSize,
scrollFrom: states.scrollOffset / (this.estimatedTotalSize - clientSize),
total,
alwaysOn: scrollbarAlwaysOn
});
const listContainer = (0, vue.h)(Container, {
class: [ns.e("window"), className],
style: windowStyle,
onScroll,
ref: "windowRef",
key: 0
}, !(0, _vue_shared.isString)(Container) ? { default: () => [InnerNode] } : [InnerNode]);
return (0, vue.h)("div", {
key: 0,
class: [ns.e("wrapper"), scrollbarAlwaysOn ? "always-on" : ""]
}, [listContainer, scrollbar]);
}
});
};
//#endregion
exports.default = createList;
//# sourceMappingURL=build-list.js.map