element-plus
Version:
A Component Library for Vue3.0
1,421 lines (1,406 loc) • 58.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var util = require('../utils/util');
var throwError = require('../utils/error');
var vue = require('vue');
var memo = require('lodash/memoize');
var isServer = require('../utils/isServer');
var raf = require('../utils/raf');
var dom = require('../utils/dom');
var getScrollBarWidth = require('../utils/scrollbar-width');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var throwError__default = /*#__PURE__*/_interopDefaultLegacy(throwError);
var memo__default = /*#__PURE__*/_interopDefaultLegacy(memo);
var isServer__default = /*#__PURE__*/_interopDefaultLegacy(isServer);
var getScrollBarWidth__default = /*#__PURE__*/_interopDefaultLegacy(getScrollBarWidth);
/**
* Make a map and return a function for checking if a key
* is in that map.
* IMPORTANT: all calls of this function must be prefixed with
* \/\*#\_\_PURE\_\_\*\/
* So that rollup can tree-shake them if necessary.
*/
const EMPTY_OBJ = (process.env.NODE_ENV !== 'production')
? Object.freeze({})
: {};
const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];
const NOOP = () => { };
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
const isFunction = (val) => typeof val === 'function';
const isObject = (val) => val !== null && typeof val === 'object';
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const DEFAULT_DYNAMIC_LIST_ITEM_SIZE = 50;
const ITEM_RENDER_EVT = "item-rendered";
const SCROLL_EVT = "scroll";
const FORWARD = "forward";
const BACKWARD = "backward";
const AUTO_ALIGNMENT = "auto";
const SMART_ALIGNMENT = "smart";
const START_ALIGNMENT = "start";
const CENTERED_ALIGNMENT = "center";
const END_ALIGNMENT = "end";
const HORIZONTAL = "horizontal";
const VERTICAL = "vertical";
const LTR = "ltr";
const RTL = "rtl";
const RTL_OFFSET_NAG = "negative";
const RTL_OFFSET_POS_ASC = "positive-ascending";
const RTL_OFFSET_POS_DESC = "positive-descending";
const DefaultListProps = {
cache: {
type: Number,
default: 2
},
className: {
type: String,
default: ""
},
containerElement: {
type: [String, Object],
default: "div"
},
data: {
type: [Array],
default: () => []
},
direction: {
type: String,
default: "ltr",
validator: (val) => {
return val === LTR || val === RTL;
}
},
estimatedItemSize: {
type: [Number]
},
height: {
type: [String, Number],
required: true
},
layout: {
type: String,
default: VERTICAL
},
initScrollOffset: {
type: Number,
default: 0
},
innerElement: {
type: [String, Object],
default: "div"
},
total: {
type: Number,
required: true
},
itemSize: {
type: [Number, Function],
required: true
},
style: {
type: [Object, String, Array],
default: () => ({})
},
useIsScrolling: {
type: Boolean,
default: false
},
width: {
type: [Number, String],
required: true
}
};
const DefaultGridProps = {
className: DefaultListProps.className,
columnCache: DefaultListProps.cache,
columnWidth: DefaultListProps.itemSize,
containerElement: DefaultListProps.containerElement,
data: DefaultListProps.data,
direction: DefaultListProps.direction,
estimatedColumnWidth: DefaultListProps.estimatedItemSize,
estimatedRowHeight: DefaultListProps.estimatedItemSize,
height: __spreadProps(__spreadValues({}, DefaultListProps.height), {
validator: (val) => util.isNumber(val)
}),
initScrollLeft: DefaultListProps.initScrollOffset,
initScrollTop: DefaultListProps.initScrollOffset,
innerElement: DefaultListProps.innerElement,
rowCache: DefaultListProps.cache,
rowHeight: DefaultListProps.itemSize,
style: DefaultListProps.style,
useIsScrolling: DefaultListProps.useIsScrolling,
width: __spreadProps(__spreadValues({}, DefaultListProps.width), {
validator: (val) => {
return util.isNumber(val);
}
}),
totalColumn: DefaultListProps.total,
totalRow: DefaultListProps.total
};
const DefaultScrollBarProps = {
layout: DefaultListProps.layout,
total: Number,
ratio: Number,
clientSize: Number,
scrollFrom: Number,
visible: Boolean
};
const SCROLLBAR_MIN_SIZE = 20;
const getScrollDir = (prev, cur) => prev < cur ? FORWARD : BACKWARD;
const isHorizontal = (dir) => dir === LTR || dir === RTL || dir === HORIZONTAL;
const isRTL = (dir) => dir === RTL;
let cachedRTLResult = null;
function getRTLOffsetType(recalculate = false) {
if (cachedRTLResult === null || recalculate) {
const outerDiv = document.createElement("div");
const outerStyle = outerDiv.style;
outerStyle.width = "50px";
outerStyle.height = "50px";
outerStyle.overflow = "scroll";
outerStyle.direction = "rtl";
const innerDiv = document.createElement("div");
const innerStyle = innerDiv.style;
innerStyle.width = "100px";
innerStyle.height = "100px";
outerDiv.appendChild(innerDiv);
document.body.appendChild(outerDiv);
if (outerDiv.scrollLeft > 0) {
cachedRTLResult = RTL_OFFSET_POS_DESC;
} else {
outerDiv.scrollLeft = 1;
if (outerDiv.scrollLeft === 0) {
cachedRTLResult = RTL_OFFSET_NAG;
} else {
cachedRTLResult = RTL_OFFSET_POS_ASC;
}
}
document.body.removeChild(outerDiv);
return cachedRTLResult;
}
return cachedRTLResult;
}
function renderThumbStyle({ move, size, bar }, layout) {
const style = {};
const translate = `translate${bar.axis}(${move}px)`;
style[bar.size] = size;
style.transform = translate;
style.msTransform = translate;
style.webkitTransform = translate;
if (layout === "horizontal") {
style.height = "100%";
} else {
style.width = "100%";
}
return style;
}
const isFF = typeof navigator !== "undefined" && isObject(navigator) && /Firefox/i.test(navigator.userAgent);
const LayoutKeys = {
[HORIZONTAL]: "deltaX",
[VERTICAL]: "deltaY"
};
const useWheel = ({
atEndEdge,
atStartEdge,
layout
}, onWheelDelta) => {
let frameHandle = null;
let offset = 0;
const hasReachedEdge = (offset2) => {
const edgeReached = offset2 < 0 && atStartEdge.value || offset2 > 0 && atEndEdge.value;
return edgeReached;
};
const onWheel = (e) => {
raf.cAF(frameHandle);
const newOffset = e[LayoutKeys[layout.value]];
if (hasReachedEdge(offset) && hasReachedEdge(offset + newOffset))
return;
offset += newOffset;
if (!isFF) {
e.preventDefault();
}
frameHandle = raf.rAF(() => {
onWheelDelta(offset);
offset = 0;
});
};
return {
hasReachedEdge,
onWheel
};
};
const BAR_MAP = {
vertical: {
offset: "offsetHeight",
scroll: "scrollTop",
scrollSize: "scrollHeight",
size: "height",
key: "vertical",
axis: "Y",
client: "clientY",
direction: "top"
},
horizontal: {
offset: "offsetWidth",
scroll: "scrollLeft",
scrollSize: "scrollWidth",
size: "width",
key: "horizontal",
axis: "X",
client: "clientX",
direction: "left"
}
};
const ScrollBar = vue.defineComponent({
name: "ElVirtualScrollBar",
props: DefaultScrollBarProps,
emits: ["scroll", "start-move", "stop-move"],
setup(props, { emit }) {
const trackRef = vue.ref(null);
const thumbRef = vue.ref(null);
let frameHandle = null;
let onselectstartStore = null;
const state = vue.reactive({
isDragging: false,
traveled: 0
});
const bar = vue.computed(() => BAR_MAP[props.layout]);
const trackStyle = vue.computed(() => ({
display: props.visible ? null : "none",
position: "absolute",
width: HORIZONTAL === props.layout ? "100%" : "6px",
height: HORIZONTAL === props.layout ? "6px" : "100%",
right: "2px",
bottom: "2px",
borderRadius: "4px"
}));
const thumbSize = vue.computed(() => {
if (props.ratio >= 100) {
return Number.POSITIVE_INFINITY;
}
if (props.ratio >= 50) {
return props.ratio * props.clientSize / 100;
}
const SCROLLBAR_MAX_SIZE = props.clientSize / 3;
return Math.floor(Math.min(Math.max(props.ratio * props.clientSize, SCROLLBAR_MIN_SIZE), SCROLLBAR_MAX_SIZE));
});
const thumbStyle = vue.computed(() => {
if (!Number.isFinite(thumbSize.value)) {
return {
display: "none"
};
}
const thumb = `${thumbSize.value}px`;
const style = renderThumbStyle({
bar: bar.value,
size: thumb,
move: state.traveled
}, props.layout);
return style;
});
const totalSteps = vue.computed(() => Math.floor(props.clientSize - thumbSize.value - 4));
const attachEvents = () => {
dom.on(window, "mousemove", onMouseMove);
dom.on(window, "mouseup", onMouseUp);
const thumbEl = thumbRef.value;
onselectstartStore = document.onselectstart;
document.onselectstart = () => false;
dom.on(thumbEl, "touchmove", onMouseMove);
dom.on(thumbEl, "touchend", onMouseUp);
};
const detachEvents = () => {
dom.off(window, "mousemove", onMouseMove);
dom.off(window, "mouseup", onMouseUp);
document.onselectstart = onselectstartStore;
onselectstartStore = null;
const thumbEl = thumbRef.value;
dom.off(thumbEl, "touchmove", onMouseMove);
dom.off(thumbEl, "touchend", onMouseUp);
};
const onThumbMouseDown = (e) => {
e.stopImmediatePropagation();
if (e.ctrlKey || [1, 2].includes(e.button)) {
return;
}
state.isDragging = true;
state[bar.value.axis] = e.currentTarget[bar.value.offset] - (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]);
emit("start-move");
attachEvents();
};
const onMouseUp = () => {
state.isDragging = false;
state[bar.value.axis] = 0;
emit("stop-move");
detachEvents();
};
const onMouseMove = (e) => {
const { isDragging } = state;
if (!isDragging)
return;
const prevPage = state[bar.value.axis];
if (!prevPage)
return;
raf.cAF(frameHandle);
const offset = (trackRef.value.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * -1;
const thumbClickPosition = thumbRef.value[bar.value.offset] - prevPage;
const distance = offset - thumbClickPosition;
frameHandle = raf.rAF(() => {
state.traveled = Math.max(2, Math.min(distance, totalSteps.value));
emit("scroll", distance, totalSteps.value);
});
};
const onScrollbarTouchStart = (e) => e.preventDefault();
vue.watch(() => props.scrollFrom, (v) => {
if (state.isDragging)
return;
state.traveled = Math.ceil(v * props.clientSize / (props.clientSize / totalSteps.value));
});
vue.onMounted(() => {
if (isServer__default['default'])
return;
dom.on(trackRef.value, "touchstart", onScrollbarTouchStart);
dom.on(thumbRef.value, "touchstart", onThumbMouseDown);
});
vue.onBeforeUnmount(() => {
dom.off(trackRef.value, "touchstart", onScrollbarTouchStart);
detachEvents();
});
return () => {
return vue.h("div", {
role: "presentation",
ref: trackRef,
class: "el-virtual-scrollbar",
style: trackStyle.value,
onMousedown: vue.withModifiers(NOOP, ["stop", "prevent"])
}, vue.h("div", {
ref: thumbRef,
class: "el-scrollbar__thumb",
style: thumbStyle.value,
onMousedown: onThumbMouseDown
}, null));
};
}
});
var __defProp$1 = Object.defineProperty;
var __defProps$1 = Object.defineProperties;
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$1 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
if (__getOwnPropSymbols$1)
for (var prop of __getOwnPropSymbols$1(b)) {
if (__propIsEnum$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
}
return a;
};
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
const createList = ({
name,
getOffset,
getItemSize,
getItemOffset,
getEstimatedTotalSize,
getStartIndexForOffset,
getStopIndexForStartIndex,
initCache,
clearCache,
validateProps
}) => {
return vue.defineComponent({
name: name != null ? name : "ElVirtualList",
props: DefaultListProps,
emits: [ITEM_RENDER_EVT, SCROLL_EVT],
setup(props, { emit, expose }) {
validateProps(props);
const instance = vue.getCurrentInstance();
const dynamicSizeCache = vue.ref(initCache(props, instance));
const windowRef = vue.ref(null);
const innerRef = vue.ref(null);
const scrollbarRef = vue.ref(null);
const states = vue.ref({
isScrolling: false,
scrollDir: "forward",
scrollOffset: util.isNumber(props.initScrollOffset) ? props.initScrollOffset : 0,
updateRequested: false,
isScrollbarDragging: false
});
const itemsToRender = vue.computed(() => {
const { total, cache } = props;
const { isScrolling, scrollDir, scrollOffset } = util.$(states);
if (total === 0) {
return [0, 0, 0, 0];
}
const startIndex = getStartIndexForOffset(props, scrollOffset, util.$(dynamicSizeCache));
const stopIndex = getStopIndexForStartIndex(props, startIndex, scrollOffset, util.$(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 = vue.computed(() => getEstimatedTotalSize(props, util.$(dynamicSizeCache)));
const _isHorizontal = vue.computed(() => isHorizontal(props.layout));
const windowStyle = vue.computed(() => [
{
position: "relative",
overflow: "hidden",
WebkitOverflowScrolling: "touch",
willChange: "transform"
},
__spreadValues$1({
direction: props.direction,
height: util.isNumber(props.height) ? `${props.height}px` : props.height,
width: util.isNumber(props.width) ? `${props.width}px` : props.width
}, props.style)
]);
const innerStyle = vue.computed(() => {
const size = util.$(estimatedTotalSize);
const horizontal = util.$(_isHorizontal);
return {
height: horizontal ? "100%" : `${size}px`,
pointerEvents: util.$(states).isScrolling ? "none" : void 0,
width: horizontal ? `${size}px` : "100%"
};
});
const clientSize = vue.computed(() => _isHorizontal.value ? props.width : props.height);
const {
onWheel
} = useWheel({
atStartEdge: vue.computed(() => states.value.scrollOffset <= 0),
atEndEdge: vue.computed(() => states.value.scrollOffset >= estimatedTotalSize.value),
layout: vue.computed(() => props.layout)
}, (offset) => {
var _a, _b;
(_b = (_a = scrollbarRef.value).onMouseUp) == null ? void 0 : _b.call(_a);
scrollTo(Math.min(states.value.scrollOffset + offset, estimatedTotalSize.value - clientSize.value));
});
const emitEvents = () => {
const { total } = props;
if (total > 0) {
const [cacheStart, cacheEnd, visibleStart, visibleEnd] = util.$(itemsToRender);
emit(ITEM_RENDER_EVT, cacheStart, cacheEnd, visibleStart, visibleEnd);
}
const { scrollDir, scrollOffset, updateRequested } = util.$(states);
emit(SCROLL_EVT, scrollDir, scrollOffset, updateRequested);
};
const scrollVertically = (e) => {
const { clientHeight, scrollHeight, scrollTop } = e.currentTarget;
const _states = util.$(states);
if (_states.scrollOffset === scrollTop) {
return;
}
const scrollOffset = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
states.value = __spreadProps$1(__spreadValues$1({}, _states), {
isScrolling: true,
scrollDir: getScrollDir(_states.scrollOffset, scrollOffset),
scrollOffset,
updateRequested: false
});
vue.nextTick(resetIsScrolling);
};
const scrollHorizontally = (e) => {
const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget;
const _states = util.$(states);
if (_states.scrollOffset === scrollLeft) {
return;
}
const { direction } = props;
let scrollOffset = scrollLeft;
if (direction === RTL) {
switch (getRTLOffsetType()) {
case RTL_OFFSET_NAG: {
scrollOffset = -scrollLeft;
break;
}
case RTL_OFFSET_POS_DESC: {
scrollOffset = scrollWidth - clientWidth - scrollLeft;
break;
}
}
}
scrollOffset = Math.max(0, Math.min(scrollOffset, scrollWidth - clientWidth));
states.value = __spreadProps$1(__spreadValues$1({}, _states), {
isScrolling: true,
scrollDir: getScrollDir(_states.scrollOffset, scrollOffset),
scrollOffset,
updateRequested: false
});
vue.nextTick(resetIsScrolling);
};
const onScroll = (e) => {
util.$(_isHorizontal) ? scrollHorizontally(e) : scrollVertically(e);
emitEvents();
};
const onScrollbarScroll = (distanceToGo, totalSteps) => {
const offset = (estimatedTotalSize.value - clientSize.value) / totalSteps * distanceToGo;
scrollTo(Math.min(estimatedTotalSize.value - clientSize.value, offset));
};
const getItemStyleCache = memo__default['default']((_, __, ___) => ({}));
const scrollTo = (offset) => {
offset = Math.max(offset, 0);
if (offset === util.$(states).scrollOffset) {
return;
}
states.value = __spreadProps$1(__spreadValues$1({}, util.$(states)), {
scrollOffset: offset,
scrollDir: getScrollDir(util.$(states).scrollOffset, offset),
updateRequested: true
});
vue.nextTick(resetIsScrolling);
};
const scrollToItem = (idx, alignment = AUTO_ALIGNMENT) => {
const { scrollOffset } = util.$(states);
idx = Math.max(0, Math.min(idx, props.total - 1));
scrollTo(getOffset(props, idx, alignment, scrollOffset, util.$(dynamicSizeCache)));
};
const getItemStyle = (idx) => {
const { direction, itemSize, layout } = props;
const itemStyleCache = getItemStyleCache(clearCache && itemSize, clearCache && layout, clearCache && direction);
let style;
if (hasOwn(itemStyleCache, String(idx))) {
style = itemStyleCache[idx];
} else {
const offset = getItemOffset(props, idx, util.$(dynamicSizeCache));
const size = getItemSize(props, idx, util.$(dynamicSizeCache));
const horizontal = util.$(_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;
vue.nextTick(() => {
getItemStyleCache(-1, null, null);
});
};
vue.onMounted(() => {
if (isServer__default['default'])
return;
const { initScrollOffset } = props;
const windowElement = util.$(windowRef);
if (util.isNumber(initScrollOffset) && windowElement !== null) {
if (util.$(_isHorizontal)) {
windowElement.scrollLeft = initScrollOffset;
} else {
windowElement.scrollTop = initScrollOffset;
}
}
emitEvents();
});
vue.onUpdated(() => {
const { direction, layout } = props;
const { scrollOffset, updateRequested } = util.$(states);
if (updateRequested && util.$(windowRef) !== null) {
const windowElement = util.$(windowRef);
if (layout === HORIZONTAL) {
if (direction === RTL) {
switch (getRTLOffsetType()) {
case "negative": {
windowElement.scrollLeft = -scrollOffset;
break;
}
case "positive-ascending": {
windowElement.scrollLeft = scrollOffset;
break;
}
default: {
const { clientWidth, scrollWidth } = windowElement;
windowElement.scrollLeft = scrollWidth - clientWidth - scrollOffset;
break;
}
}
} else {
windowElement.scrollLeft = scrollOffset;
}
} else {
windowElement.scrollTop = scrollOffset;
}
}
});
const api = {
clientSize,
estimatedTotalSize,
windowStyle,
windowRef,
innerRef,
innerStyle,
itemsToRender,
scrollbarRef,
states,
getItemStyle,
onScroll,
onScrollbarScroll,
onWheel,
scrollTo,
scrollToItem
};
expose({
windowRef,
innerRef,
getItemStyleCache,
scrollTo,
scrollToItem,
states
});
return api;
},
render(ctx) {
var _a;
const {
$slots,
className,
clientSize,
containerElement,
data,
getItemStyle,
innerElement,
itemsToRender,
innerStyle,
layout,
total,
onScroll,
onScrollbarScroll,
onWheel,
states,
useIsScrolling,
windowStyle
} = ctx;
const [start, end] = itemsToRender;
const Container = vue.resolveDynamicComponent(containerElement);
const Inner = vue.resolveDynamicComponent(innerElement);
const children = [];
if (total > 0) {
for (let i = start; i <= end; i++) {
children.push((_a = $slots.default) == null ? void 0 : _a.call($slots, {
data,
key: i,
index: i,
isScrolling: useIsScrolling ? states.isScrolling : void 0,
style: getItemStyle(i)
}));
}
}
const InnerNode = [vue.h(Inner, {
style: innerStyle,
ref: "innerRef"
}, !util.isString(Inner) ? {
default: () => children
} : children)];
const scrollbar = vue.h(ScrollBar, {
ref: "scrollbarRef",
clientSize,
layout,
onScroll: onScrollbarScroll,
ratio: clientSize * 100 / this.estimatedTotalSize,
scrollFrom: states.scrollOffset / (this.estimatedTotalSize - clientSize),
total,
visible: true
});
const listContainer = vue.h(Container, {
class: className,
style: windowStyle,
onScroll,
onWheel,
ref: "windowRef",
key: 0
}, !util.isString(Container) ? { default: () => [InnerNode] } : [InnerNode]);
return vue.h("div", {
key: 0,
class: "el-vl__wrapper"
}, [
listContainer,
scrollbar
]);
}
});
};
const FixedSizeList = createList({
name: "ElFixedSizeList",
getItemOffset: ({ itemSize }, index) => index * itemSize,
getItemSize: ({ itemSize }) => itemSize,
getEstimatedTotalSize: ({ total, itemSize }) => itemSize * total,
getOffset: ({ height, total, itemSize, layout, width }, index, alignment, scrollOffset) => {
const size = isHorizontal(layout) ? width : height;
if (process.env.ENV !== "production" && util.isString(size)) {
throwError__default['default']("[ElVirtualList]", `
You should set
width/height
to number when your layout is
horizontal/vertical
`);
}
const lastItemOffset = Math.max(0, total * itemSize - size);
const maxOffset = Math.min(lastItemOffset, index * itemSize);
const minOffset = Math.max(0, (index + 1) * itemSize - size);
if (alignment === SMART_ALIGNMENT) {
if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
alignment = AUTO_ALIGNMENT;
} else {
alignment = CENTERED_ALIGNMENT;
}
}
switch (alignment) {
case START_ALIGNMENT: {
return maxOffset;
}
case END_ALIGNMENT: {
return minOffset;
}
case CENTERED_ALIGNMENT: {
const middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
if (middleOffset < Math.ceil(size / 2)) {
return 0;
} else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
return lastItemOffset;
} else {
return middleOffset;
}
}
case AUTO_ALIGNMENT:
default: {
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
} else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
}
}
}
},
getStartIndexForOffset: ({ total, itemSize }, offset) => Math.max(0, Math.min(total - 1, Math.floor(offset / itemSize))),
getStopIndexForStartIndex: ({ height, total, itemSize, layout, width }, startIndex, scrollOffset) => {
const offset = startIndex * itemSize;
const size = isHorizontal(layout) ? width : height;
const numVisibleItems = Math.ceil((size + scrollOffset - offset) / itemSize);
return Math.max(0, Math.min(total - 1, startIndex + numVisibleItems - 1));
},
initCache() {
return void 0;
},
clearCache: true,
validateProps() {
}
});
const SCOPE = "ElDynamicSizeList";
const getItemFromCache = (props, index, listCache) => {
const { itemSize } = props;
const { items, lastVisitedIndex } = listCache;
if (index > lastVisitedIndex) {
let offset = 0;
if (lastVisitedIndex >= 0) {
const item = items[lastVisitedIndex];
offset = item.offset + item.size;
}
for (let i = lastVisitedIndex + 1; i <= index; i++) {
const size = itemSize(i);
items[i] = {
offset,
size
};
offset += size;
}
listCache.lastVisitedIndex = index;
}
return items[index];
};
const findItem = (props, listCache, offset) => {
const { items, lastVisitedIndex } = listCache;
const lastVisitedOffset = lastVisitedIndex > 0 ? items[lastVisitedIndex].offset : 0;
if (lastVisitedOffset >= offset) {
return bs(props, listCache, 0, lastVisitedIndex, offset);
}
return es(props, listCache, Math.max(0, lastVisitedIndex), offset);
};
const bs = (props, listCache, low, high, offset) => {
while (low <= high) {
const mid = low + Math.floor((high - low) / 2);
const currentOffset = getItemFromCache(props, mid, listCache).offset;
if (currentOffset === offset) {
return mid;
} else if (currentOffset < offset) {
low = mid + 1;
} else if (currentOffset > offset) {
high = mid - 1;
}
}
return Math.max(0, low - 1);
};
const es = (props, listCache, index, offset) => {
const { total } = props;
let exponent = 1;
while (index < total && getItemFromCache(props, index, listCache).offset < offset) {
index += exponent;
exponent *= 2;
}
return bs(props, listCache, Math.floor(index / 2), Math.min(index, total - 1), offset);
};
const getEstimatedTotalSize = ({ total }, { items, estimatedItemSize, lastVisitedIndex }) => {
let totalSizeOfMeasuredItems = 0;
if (lastVisitedIndex >= total) {
lastVisitedIndex = total - 1;
}
if (lastVisitedIndex >= 0) {
const item = items[lastVisitedIndex];
totalSizeOfMeasuredItems = item.offset + item.size;
}
const numUnmeasuredItems = total - lastVisitedIndex - 1;
const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedItemSize;
return totalSizeOfMeasuredItems + totalSizeOfUnmeasuredItems;
};
const DynamicSizeList = createList({
name: "ElDynamicSizeList",
getItemOffset: (props, index, listCache) => getItemFromCache(props, index, listCache).offset,
getItemSize: (_, index, { items }) => items[index].size,
getEstimatedTotalSize,
getOffset: (props, index, alignment, scrollOffset, listCache) => {
const { height, layout, width } = props;
const size = isHorizontal(layout) ? width : height;
const item = getItemFromCache(props, index, listCache);
const estimatedTotalSize = getEstimatedTotalSize(props, listCache);
const maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, item.offset));
const minOffset = Math.max(0, item.offset - size + item.size);
if (alignment === SMART_ALIGNMENT) {
if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
alignment = AUTO_ALIGNMENT;
} else {
alignment = CENTERED_ALIGNMENT;
}
}
switch (alignment) {
case START_ALIGNMENT: {
return maxOffset;
}
case END_ALIGNMENT: {
return minOffset;
}
case CENTERED_ALIGNMENT: {
return Math.round(minOffset + (maxOffset - minOffset) / 2);
}
case AUTO_ALIGNMENT:
default: {
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
} else if (scrollOffset < minOffset) {
return minOffset;
} else {
return maxOffset;
}
}
}
},
getStartIndexForOffset: (props, offset, listCache) => findItem(props, listCache, offset),
getStopIndexForStartIndex: (props, startIndex, scrollOffset, listCache) => {
const { height, total, layout, width } = props;
const size = isHorizontal(layout) ? width : height;
const item = getItemFromCache(props, startIndex, listCache);
const maxOffset = scrollOffset + size;
let offset = item.offset + item.size;
let stopIndex = startIndex;
while (stopIndex < total - 1 && offset < maxOffset) {
stopIndex++;
offset += getItemFromCache(props, stopIndex, listCache).size;
}
return stopIndex;
},
initCache({ estimatedItemSize = DEFAULT_DYNAMIC_LIST_ITEM_SIZE }, instance) {
const cache = {
items: {},
estimatedItemSize,
lastVisitedIndex: -1
};
cache.clearCacheAfterIndex = (index, forceUpdate = true) => {
cache.lastVisitedIndex = Math.min(cache.lastVisitedIndex, index - 1);
instance.exposed.getItemStyleCache(-1);
if (forceUpdate) {
instance.proxy.$forceUpdate();
}
};
return cache;
},
clearCache: false,
validateProps: ({ itemSize }) => {
if (process.env.NODE_ENV !== "production") {
if (typeof itemSize !== "function") {
throwError__default['default'](SCOPE, `
itemSize is required as function, but the given value was ${typeof itemSize}
`);
}
}
}
});
var __defProp$2 = Object.defineProperty;
var __defProps$2 = Object.defineProperties;
var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$2 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
if (__getOwnPropSymbols$2)
for (var prop of __getOwnPropSymbols$2(b)) {
if (__propIsEnum$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
}
return a;
};
var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
const createGrid = ({
name,
clearCache,
getColumnPosition,
getColumnStartIndexForOffset,
getColumnStopIndexForStartIndex,
getEstimatedTotalHeight,
getEstimatedTotalWidth,
getColumnOffset,
getRowOffset,
getRowPosition,
getRowStartIndexForOffset,
getRowStopIndexForStartIndex,
initCache,
validateProps
}) => {
return vue.defineComponent({
name: name != null ? name : "ElVirtualList",
props: DefaultGridProps,
emits: [ITEM_RENDER_EVT, SCROLL_EVT],
setup(props, { emit, expose }) {
validateProps(props);
const instance = vue.getCurrentInstance();
const cache = vue.ref(initCache(props, instance));
const windowRef = vue.ref(null);
const innerRef = vue.ref(null);
const states = vue.ref({
isScrolling: false,
scrollLeft: util.isNumber(props.initScrollLeft) ? props.initScrollLeft : 0,
scrollTop: util.isNumber(props.initScrollTop) ? props.initScrollTop : 0,
updateRequested: false,
xAxisScrollDir: FORWARD,
yAxisScrollDir: FORWARD
});
const columnsToRender = vue.computed(() => {
const { totalColumn, totalRow, columnCache } = props;
const { isScrolling, xAxisScrollDir, scrollLeft } = util.$(states);
if (totalColumn === 0 || totalRow === 0) {
return [0, 0, 0, 0];
}
const startIndex = getColumnStartIndexForOffset(props, scrollLeft, util.$(cache));
const stopIndex = getColumnStopIndexForStartIndex(props, startIndex, scrollLeft, util.$(cache));
const cacheBackward = !isScrolling || xAxisScrollDir === BACKWARD ? Math.max(1, columnCache) : 1;
const cacheForward = !isScrolling || xAxisScrollDir === FORWARD ? Math.max(1, columnCache) : 1;
return [
Math.max(0, startIndex - cacheBackward),
Math.max(0, Math.min(totalColumn - 1, stopIndex + cacheForward)),
startIndex,
stopIndex
];
});
const rowsToRender = vue.computed(() => {
const { totalColumn, totalRow, rowCache } = props;
const { isScrolling, yAxisScrollDir, scrollTop } = util.$(states);
if (totalColumn === 0 || totalRow === 0) {
return [0, 0, 0, 0];
}
const startIndex = getRowStartIndexForOffset(props, scrollTop, util.$(cache));
const stopIndex = getRowStopIndexForStartIndex(props, startIndex, scrollTop, util.$(cache));
const cacheBackward = !isScrolling || yAxisScrollDir === BACKWARD ? Math.max(1, rowCache) : 1;
const cacheForward = !isScrolling || yAxisScrollDir === FORWARD ? Math.max(1, rowCache) : 1;
return [
Math.max(0, startIndex - cacheBackward),
Math.max(0, Math.min(totalRow - 1, stopIndex + cacheForward)),
startIndex,
stopIndex
];
});
const estimatedTotalHeight = vue.computed(() => getEstimatedTotalHeight(props, util.$(cache)));
const estimatedTotalWidth = vue.computed(() => getEstimatedTotalWidth(props, util.$(cache)));
const windowStyle = vue.computed(() => [
{
position: "relative",
overflow: "auto",
WebkitOverflowScrolling: "touch",
willChange: "transform"
},
__spreadValues$2({
direction: props.direction,
height: util.isNumber(props.height) ? `${props.height}px` : props.height,
width: util.isNumber(props.width) ? `${props.width}px` : props.width
}, props.style)
]);
const innerStyle = vue.computed(() => {
const width = `${util.$(estimatedTotalWidth)}px`;
const height = `${util.$(estimatedTotalHeight)}px`;
return {
height,
pointerEvents: util.$(states).isScrolling ? "none" : void 0,
width
};
});
const emitEvents = () => {
const { totalColumn, totalRow } = props;
if (totalColumn > 0 && totalRow > 0) {
const [columnCacheStart, columnCacheEnd, columnVisibleStart, columnVisibleEnd] = util.$(columnsToRender);
const [rowCacheStart, rowCacheEnd, rowVisibleStart, rowVisibleEnd] = util.$(rowsToRender);
emit(ITEM_RENDER_EVT, columnCacheStart, columnCacheEnd, rowCacheStart, rowCacheEnd, columnVisibleStart, columnVisibleEnd, rowVisibleStart, rowVisibleEnd);
}
const { scrollLeft, scrollTop, updateRequested, xAxisScrollDir, yAxisScrollDir } = util.$(states);
emit(SCROLL_EVT, xAxisScrollDir, scrollLeft, yAxisScrollDir, scrollTop, updateRequested);
};
const onScroll = (e) => {
const {
clientHeight,
clientWidth,
scrollHeight,
scrollLeft,
scrollTop,
scrollWidth
} = e.currentTarget;
const _states = util.$(states);
if (_states.scrollTop === scrollTop && _states.scrollLeft === scrollLeft) {
return;
}
let _scrollLeft = scrollLeft;
if (isRTL(props.direction)) {
switch (getRTLOffsetType()) {
case RTL_OFFSET_NAG:
_scrollLeft = -scrollLeft;
break;
case RTL_OFFSET_POS_DESC:
_scrollLeft = scrollWidth - clientWidth - scrollLeft;
break;
}
}
states.value = __spreadProps$2(__spreadValues$2({}, _states), {
isScrolling: true,
scrollLeft: _scrollLeft,
scrollTop: Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight)),
updateRequested: false,
xAxisScrollDir: getScrollDir(_states.scrollLeft, _scrollLeft),
yAxisScrollDir: getScrollDir(_states.scrollTop, scrollTop)
});
vue.nextTick(resetIsScrolling);
emitEvents();
};
const getItemStyleCache = memo__default['default']((_, __, ___) => ({}));
const scrollTo = ({
scrollLeft,
scrollTop
}) => {
scrollLeft = Math.max(scrollLeft, 0);
scrollTop = Math.max(scrollTop, 0);
const _states = util.$(states);
if (scrollTop === _states.scrollTop && scrollLeft === _states.scrollLeft) {
return;
}
states.value = __spreadProps$2(__spreadValues$2({}, _states), {
xAxisScrollDir: getScrollDir(_states.scrollLeft, scrollLeft),
yAxisScrollDir: getScrollDir(_states.scrollTop, scrollTop),
scrollLeft,
scrollTop,
updateRequested: true
});
vue.nextTick(resetIsScrolling);
};
const scrollToItem = (rowIndex = 0, columnIdx = 0, alignment = AUTO_ALIGNMENT) => {
const _states = util.$(states);
columnIdx = Math.max(0, Math.min(columnIdx, props.totalColumn - 1));
rowIndex = Math.max(0, Math.min(rowIndex, props.totalRow - 1));
const scrollBarWidth = getScrollBarWidth__default['default']();
const _cache = util.$(cache);
const estimatedHeight = getEstimatedTotalHeight(props, _cache);
const estimatedWidth = getEstimatedTotalWidth(props, _cache);
scrollTo({
scrollLeft: getColumnOffset(props, columnIdx, alignment, _states.scrollLeft, _cache, estimatedWidth > props.width ? scrollBarWidth : 0),
scrollTop: getRowOffset(props, rowIndex, alignment, _states.scrollTop, _cache, estimatedHeight > props.height ? scrollBarWidth : 0)
});
};
const getItemStyle = (rowIndex, columnIndex) => {
const { columnWidth, direction, rowHeight } = props;
const itemStyleCache = getItemStyleCache(clearCache && columnWidth, clearCache && rowHeight, clearCache && direction);
const key = `${rowIndex},${columnIndex}`;
if (hasOwn(itemStyleCache, key)) {
return itemStyleCache[key];
} else {
const [, left] = getColumnPosition(props, columnIndex, util.$(cache));
const _cache = util.$(cache);
const rtl = isRTL(direction);
const [height, top] = getRowPosition(props, rowIndex, _cache);
const [width] = getColumnPosition(props, columnIndex, _cache);
itemStyleCache[key] = {
position: "absolute",
left: rtl ? void 0 : `${left}px`,
right: rtl ? `${left}px` : void 0,
top: `${top}px`,
height: `${height}px`,
width: `${width}px`
};
return itemStyleCache[key];
}
};
const resetIsScrolling = () => {
states.value.isScrolling = false;
vue.nextTick(() => {
getItemStyleCache(-1, null, null);
});
};
vue.onMounted(() => {
if (isServer__default['default'])
return;
const { initScrollLeft, initScrollTop } = props;
const windowElement = util.$(windowRef);
if (windowElement !== null) {
if (util.isNumber(initScrollLeft)) {
windowElement.scrollLeft = initScrollLeft;
}
if (util.isNumber(initScrollTop)) {
windowElement.scrollTop = initScrollTop;
}
}
emitEvents();
});
vue.onUpdated(() => {
const { direction } = props;
const { scrollLeft, scrollTop, updateRequested } = util.$(states);
if (updateRequested && util.$(windowRef) !== null) {
const windowElement = util.$(windowRef);
if (direction === RTL) {
switch (getRTLOffsetType()) {
case RTL_OFFSET_NAG: {
windowElement.scrollLeft = -scrollLeft;
break;
}
case RTL_OFFSET_POS_ASC: {
windowElement.scrollLeft = scrollLeft;
break;
}
default: {
const { clientWidth, scrollWidth } = windowElement;
windowElement.scrollLeft = scrollWidth - clientWidth - scrollLeft;
break;
}
}
} else {
windowElement.scrollLeft = Math.max(0, scrollLeft);
}
windowElement.scrollTop = Math.max(0, scrollTop);
}
});
const api = {
windowStyle,
windowRef,
columnsToRender,
innerRef,
innerStyle,
states,
rowsToRender,
getItemStyle,
onScroll,
scrollTo,
scrollToItem
};
expose({
windowRef,
innerRef,
getItemStyleCache,
scrollTo,
scrollToItem,
states
});
return api;
},
render(ctx) {
var _a;
const {
$slots,
className,
containerElement,
columnsToRender,
data,
getItemStyle,
innerElement,
innerStyle,
rowsToRender,
onScroll,
states,
useIsScrolling,
windowStyle,
totalColumn,
totalRow
} = ctx;
const [columnStart, columnEnd] = columnsToRender;
const [rowStart, rowEnd] = rowsToRender;
const Container = vue.resolveDynamicComponent(containerElement);
const Inner = vue.resolveDynamicComponent(innerElement);
const children = [];
if (totalRow > 0 && totalColumn > 0) {
for (let row = rowStart; row <= rowEnd; row++) {
for (let column = columnStart; column <= columnEnd; column++) {
children.push((_a = $slots.default) == null ? void 0 : _a.call($slots, {
columnIndex: column,
data,
key: column,
isScrolling: useIsScrolling ? states.isScrolling : void 0,
style: getItemStyle(row, column),
rowIndex: row
}));
}
}
}
const InnerNode = [vue.h(Inner, {
style: innerStyle,
ref: "innerRef"
}, !util.isString(Inner) ? {
default: () => children
} : children)];
return vue.h(Container, {
class: className,
style: windowStyle,
onScroll,
ref: "windowRef"
}, !util.isString(Container) ? { default: () => InnerNode } : InnerNode);
}
});
};
const SCOPE$1 = "ElFixedSizeGrid";
const FixedSizeGrid = createGrid({
name: "ElFixedSizeGrid",
getColumnPosition: ({ columnWidth }, index) => [
columnWidth,
index * columnWidth
],
getRowPosition: ({ rowHeight }, index) => [
rowHeight,
index * rowHeight
],
getEstimatedTotalHeight: ({ totalRow, rowHeight }) => rowHeight * totalRow,
getEstimatedTotalWidth: ({ totalColumn, columnWidth }) => columnWidth * totalColumn,
getColumnOffset: ({ totalColumn, columnWidth, width }, columnIndex, alignment, scrollLeft, _, scrollBarWidth) => {
width = Number(width);
const lastColumnOffset = Math.max(0, totalColumn * columnWidth - width);
const maxOffset = Math.min(lastColumnOffset, columnIndex * columnWidth);
const minOffset = Math.max(0, columnIndex * columnWidth - width + scrollBarWidth + columnWidth);
if (alignment === "smart") {
if (scrollLeft >= minOffset - width && scrollLeft <= maxOffset + width) {
alignment = AUTO_ALIGNMENT;
} else {
alignment = CENTERED_ALIGNMENT;
}
}
switch (alignment) {
case START_ALIGNMENT:
return maxOffset;
case END_ALIGNMENT:
return minOffset;
case CENTERED_ALIGNMENT:
const middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
if (middleOffset < Math.ceil(width / 2)) {
return 0;
} else if (middleOffset > lastColumnOffset + Math.floor(width / 2)) {
return lastColumnOffset;
} else {
return middleOffset;
}
case AUTO_ALIGNMENT:
default:
if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
return scrollLeft;
} else if (minOffset > maxOffset) {
return minOffset;
} else if (scrollLeft < minOffset) {
return minOffset;
} else {
return maxOffset;
}
}
},
getRowOffset: ({ rowHeight, height, totalRow }, rowIndex, align, scrollTop, _, scrollBarWidth) => {
height = Number(height);
const lastRowOffset = Math.max(0, totalRow * rowHeight - height);
const maxOffset = Math.min(lastRowOffset, rowIndex * rowHeight);
const minOffset = Math.max(0, rowIndex * rowHeight - height + scrollBarWidth + rowHeight);
if (align === SMART_ALIGNMENT) {
if (scrollTop >= minOffset - height && scrollTop <= maxOffset + height) {
align = AUTO_ALIGNMENT;
} else {
align = CENTERED_ALIGNMENT;
}
}
switch (align) {
case START_ALIGNMENT:
return maxOffset;
case END_ALIGNMENT:
return minOffset;
case CENTERED_ALIGNMENT:
const middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
if (middleOffset < Math.ceil(height / 2)) {
return 0;
} else if (middleOffset > lastRowOffset + Math.floor(height / 2)) {
return lastRowOffset;
} else {
return middleOffset;
}
case AUTO_ALIGNMENT:
default:
if (scrollTop >= minOffset && scrollTop <= maxOffset) {
return scrollTop;
} else if (minOffset > maxOffset) {
return minOffset;
} else if (scrollTop < minOffset) {
return minOffset;
} else {
return maxOffset;
}
}
},
getColumnStartIndexForOffset: ({ columnWidth, totalColumn }, scrollLeft) => Math.max(0, Math.min(totalColumn - 1, Math.floor(scrollLeft / columnWidth))),
getColumnStopIndexForStartIndex: ({ columnWidth, totalColumn, width }, startIndex, scrollLeft) => {
const left = startIndex * columnWidth;
const visibleColumnsCount = Math.ceil((width + scrollLeft - left) / columnWidth);
return Math.max(0, Math.min(totalColumn - 1, startIndex + visibleColumnsCount - 1));
},
getRowStartIndexForOffset: ({ rowHeight, totalRow }, scrollTop) => Math.max(0, Math.min(totalRow - 1, Math.floor(scrollTop / rowHeight))),
getRowStopIndexForStartIndex: ({ rowHeight, totalRow, height }, startIndex, scrollTop) => {
const top = startIndex * rowHeight;
const numVisibleRows = Math.ceil((height + scrollTop - top) / rowHeight);
return Math.max(0, Math.min(totalRow - 1, startIndex + numVisibleRows - 1));
}