feat: update vittual-list
parent
b9f9dad4c7
commit
f6752899e2
|
@ -1 +1 @@
|
||||||
Subproject commit 955716e4e9533bc628c651d6ba6c8d1eb9b21a9d
|
Subproject commit 79d49c0ff31a4f505ccd5bc3ad238c08f9925212
|
|
@ -0,0 +1,69 @@
|
||||||
|
const attributes = `accept acceptCharset accessKey action allowFullScreen allowTransparency
|
||||||
|
alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
|
||||||
|
charSet checked classID className colSpan cols content contentEditable contextMenu
|
||||||
|
controls coords crossOrigin data dateTime default defer dir disabled download draggable
|
||||||
|
encType form formAction formEncType formMethod formNoValidate formTarget frameBorder
|
||||||
|
headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity
|
||||||
|
is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media
|
||||||
|
mediaGroup method min minLength multiple muted name noValidate nonce open
|
||||||
|
optimum pattern placeholder poster preload radioGroup readOnly rel required
|
||||||
|
reversed role rowSpan rows sandbox scope scoped scrolling seamless selected
|
||||||
|
shape size sizes span spellCheck src srcDoc srcLang srcSet start step style
|
||||||
|
summary tabIndex target title type useMap value width wmode wrap`;
|
||||||
|
|
||||||
|
const eventsName = `onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown
|
||||||
|
onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick
|
||||||
|
onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown
|
||||||
|
onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel
|
||||||
|
onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough
|
||||||
|
onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata
|
||||||
|
onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError`;
|
||||||
|
|
||||||
|
const propList = `${attributes} ${eventsName}`.split(/[\s\n]+/);
|
||||||
|
|
||||||
|
/* eslint-enable max-len */
|
||||||
|
const ariaPrefix = 'aria-';
|
||||||
|
const dataPrefix = 'data-';
|
||||||
|
|
||||||
|
function match(key, prefix) {
|
||||||
|
return key.indexOf(prefix) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picker props from exist props with filter
|
||||||
|
* @param props Passed props
|
||||||
|
* @param ariaOnly boolean | { aria?: boolean; data?: boolean; attr?: boolean; } filter config
|
||||||
|
*/
|
||||||
|
export default function pickAttrs(props, ariaOnly = false) {
|
||||||
|
let mergedConfig;
|
||||||
|
if (ariaOnly === false) {
|
||||||
|
mergedConfig = {
|
||||||
|
aria: true,
|
||||||
|
data: true,
|
||||||
|
attr: true,
|
||||||
|
};
|
||||||
|
} else if (ariaOnly === true) {
|
||||||
|
mergedConfig = {
|
||||||
|
aria: true,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
mergedConfig = {
|
||||||
|
...ariaOnly,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrs = {};
|
||||||
|
Object.keys(props).forEach(key => {
|
||||||
|
if (
|
||||||
|
// Aria
|
||||||
|
(mergedConfig.aria && (key === 'role' || match(key, ariaPrefix))) ||
|
||||||
|
// Data
|
||||||
|
(mergedConfig.data && match(key, dataPrefix)) ||
|
||||||
|
// Attr
|
||||||
|
(mergedConfig.attr && propList.includes(key))
|
||||||
|
) {
|
||||||
|
attrs[key] = props[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return attrs;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
},
|
||||||
|
isSelectOptGroup: true,
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
},
|
||||||
|
isSelectOption: true,
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,348 @@
|
||||||
|
import TransBtn from './TransBtn';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
import KeyCode from '../_util/KeyCode';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import pickAttrs from '../_util/pickAttrs';
|
||||||
|
import { isValidElement } from '../_util/props-util';
|
||||||
|
import createRef from '../_util/createRef';
|
||||||
|
import { computed, reactive, watch } from 'vue';
|
||||||
|
import List from '../vc-virtual-list/List';
|
||||||
|
|
||||||
|
const OptionListProps = {
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
id: PropTypes.string,
|
||||||
|
options: PropTypes.array,
|
||||||
|
flattenOptions: PropTypes.array,
|
||||||
|
height: PropTypes.number,
|
||||||
|
itemHeight: PropTypes.number,
|
||||||
|
values: PropTypes.any,
|
||||||
|
multiple: PropTypes.bool,
|
||||||
|
open: PropTypes.bool,
|
||||||
|
defaultActiveFirstOption: PropTypes.bool,
|
||||||
|
notFoundContent: PropTypes.any,
|
||||||
|
menuItemSelectedIcon: PropTypes.any,
|
||||||
|
childrenAsData: PropTypes.bool,
|
||||||
|
searchValue: PropTypes.string,
|
||||||
|
virtual: PropTypes.bool,
|
||||||
|
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
onToggleOpen: PropTypes.func,
|
||||||
|
/** Tell Select that some value is now active to make accessibility work */
|
||||||
|
onActiveValue: PropTypes.func,
|
||||||
|
onScroll: PropTypes.func,
|
||||||
|
|
||||||
|
/** Tell Select that mouse enter the popup to force re-render */
|
||||||
|
onMouseenter: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using virtual list of option display.
|
||||||
|
* Will fallback to dom if use customize render.
|
||||||
|
*/
|
||||||
|
const OptionList = {
|
||||||
|
props: OptionListProps,
|
||||||
|
name: 'OptionList',
|
||||||
|
inheritAttrs: false,
|
||||||
|
setup(props) {
|
||||||
|
const itemPrefixCls = computed(() => `${props.prefixCls}-item`);
|
||||||
|
|
||||||
|
// =========================== List ===========================
|
||||||
|
const listRef = createRef();
|
||||||
|
|
||||||
|
const onListMouseDown = event => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const scrollIntoView = index => {
|
||||||
|
if (listRef.current) {
|
||||||
|
listRef.current.scrollTo({ index });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================== Active ==========================
|
||||||
|
const getEnabledActiveIndex = (index, offset = 1) => {
|
||||||
|
const len = props.flattenOptions.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i += 1) {
|
||||||
|
const current = (index + i * offset + len) % len;
|
||||||
|
|
||||||
|
const { group, data } = props.flattenOptions[current];
|
||||||
|
if (!group && !data.disabled) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
const state = reactive({
|
||||||
|
activeIndex: getEnabledActiveIndex(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
const setActive = (index, fromKeyboard = false) => {
|
||||||
|
state.activeIndex = index;
|
||||||
|
const info = { source: fromKeyboard ? 'keyboard' : 'mouse' };
|
||||||
|
|
||||||
|
// Trigger active event
|
||||||
|
const flattenItem = props.flattenOptions[index];
|
||||||
|
if (!flattenItem) {
|
||||||
|
props.onActiveValue(null, -1, info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.onActiveValue(flattenItem.data.value, index, info);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Auto active first item when list length or searchValue changed
|
||||||
|
|
||||||
|
watch([props.flattenOptions.length, props.searchValue], () => {
|
||||||
|
setActive(props.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
|
||||||
|
});
|
||||||
|
// Auto scroll to item position in single mode
|
||||||
|
watch(props.open, () => {
|
||||||
|
/**
|
||||||
|
* React will skip `onChange` when component update.
|
||||||
|
* `setActive` function will call root accessibility state update which makes re-render.
|
||||||
|
* So we need to delay to let Input component trigger onChange first.
|
||||||
|
*/
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
if (!props.multiple && props.open && props.values.size === 1) {
|
||||||
|
const value = Array.from(props.values)[0];
|
||||||
|
const index = props.flattenOptions.findIndex(({ data }) => data.value === value);
|
||||||
|
setActive(index);
|
||||||
|
scrollIntoView(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================== Values ==========================
|
||||||
|
const onSelectValue = value => {
|
||||||
|
if (value !== undefined) {
|
||||||
|
props.onSelect(value, { selected: !props.values.has(value) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single mode should always close by select
|
||||||
|
if (!props.multiple) {
|
||||||
|
props.onToggleOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderItem(index) {
|
||||||
|
const item = props.flattenOptions[index];
|
||||||
|
if (!item) return null;
|
||||||
|
|
||||||
|
const itemData = item.data || {};
|
||||||
|
const { value, label, children } = itemData;
|
||||||
|
const attrs = pickAttrs(itemData, true);
|
||||||
|
const mergedLabel = props.childrenAsData ? children : label;
|
||||||
|
return item ? (
|
||||||
|
<div
|
||||||
|
aria-label={typeof mergedLabel === 'string' ? mergedLabel : null}
|
||||||
|
{...attrs}
|
||||||
|
key={index}
|
||||||
|
role="option"
|
||||||
|
id={`${props.id}_list_${index}`}
|
||||||
|
aria-selected={props.values.has(value)}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
renderItem,
|
||||||
|
listRef,
|
||||||
|
state,
|
||||||
|
onListMouseDown,
|
||||||
|
itemPrefixCls,
|
||||||
|
setActive,
|
||||||
|
onSelectValue,
|
||||||
|
onKeydown: event => {
|
||||||
|
const { which } = event;
|
||||||
|
switch (which) {
|
||||||
|
// >>> Arrow keys
|
||||||
|
case KeyCode.UP:
|
||||||
|
case KeyCode.DOWN: {
|
||||||
|
let offset = 0;
|
||||||
|
if (which === KeyCode.UP) {
|
||||||
|
offset = -1;
|
||||||
|
} else if (which === KeyCode.DOWN) {
|
||||||
|
offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset !== 0) {
|
||||||
|
const nextActiveIndex = getEnabledActiveIndex(state.activeIndex + offset, offset);
|
||||||
|
scrollIntoView(nextActiveIndex);
|
||||||
|
setActive(nextActiveIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// >>> Select
|
||||||
|
case KeyCode.ENTER: {
|
||||||
|
// value
|
||||||
|
const item = props.flattenOptions[state.activeIndex];
|
||||||
|
if (item && !item.data.disabled) {
|
||||||
|
onSelectValue(item.data.value);
|
||||||
|
} else {
|
||||||
|
onSelectValue(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.open) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// >>> Close
|
||||||
|
case KeyCode.ESC: {
|
||||||
|
props.onToggleOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onKeyup: () => {},
|
||||||
|
|
||||||
|
scrollTo: index => {
|
||||||
|
scrollIntoView(index);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
const { renderItem, listRef, onListMouseDown, itemPrefixCls, setActive, onSelectValue } = this;
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
childrenAsData,
|
||||||
|
values,
|
||||||
|
height,
|
||||||
|
itemHeight,
|
||||||
|
flattenOptions,
|
||||||
|
menuItemSelectedIcon,
|
||||||
|
notFoundContent,
|
||||||
|
virtual,
|
||||||
|
onScroll,
|
||||||
|
onMouseenter,
|
||||||
|
} = this.$props;
|
||||||
|
const { activeIndex } = this.state;
|
||||||
|
// ========================== Render ==========================
|
||||||
|
if (flattenOptions.length === 0) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="listbox"
|
||||||
|
id={`${id}_list`}
|
||||||
|
class={`${itemPrefixCls}-empty`}
|
||||||
|
onMousedown={onListMouseDown}
|
||||||
|
>
|
||||||
|
{notFoundContent}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div role="listbox" id={`${id}_list`} style={{ height: 0, width: 0, overflow: 'hidden' }}>
|
||||||
|
{renderItem(activeIndex - 1)}
|
||||||
|
{renderItem(activeIndex)}
|
||||||
|
{renderItem(activeIndex + 1)}
|
||||||
|
</div>
|
||||||
|
<List
|
||||||
|
itemKey="key"
|
||||||
|
ref={listRef}
|
||||||
|
data={flattenOptions}
|
||||||
|
height={height}
|
||||||
|
itemHeight={itemHeight}
|
||||||
|
fullHeight={false}
|
||||||
|
onMousedown={onListMouseDown}
|
||||||
|
onScroll={onScroll}
|
||||||
|
virtual={virtual}
|
||||||
|
onMouseenter={onMouseenter}
|
||||||
|
>
|
||||||
|
{({ group, groupOption, data }, itemIndex) => {
|
||||||
|
const { label, key } = data;
|
||||||
|
|
||||||
|
// Group
|
||||||
|
if (group) {
|
||||||
|
return (
|
||||||
|
<div class={classNames(itemPrefixCls, `${itemPrefixCls}-group`)}>
|
||||||
|
{label !== undefined ? label : key}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
disabled,
|
||||||
|
value,
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
class: cls,
|
||||||
|
className,
|
||||||
|
...otherProps
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
// Option
|
||||||
|
const selected = values.has(value);
|
||||||
|
|
||||||
|
const optionPrefixCls = `${itemPrefixCls}-option`;
|
||||||
|
const optionClassName = classNames(itemPrefixCls, optionPrefixCls, cls, className, {
|
||||||
|
[`${optionPrefixCls}-grouped`]: groupOption,
|
||||||
|
[`${optionPrefixCls}-active`]: activeIndex === itemIndex && !disabled,
|
||||||
|
[`${optionPrefixCls}-disabled`]: disabled,
|
||||||
|
[`${optionPrefixCls}-selected`]: selected,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mergedLabel = childrenAsData ? children : label;
|
||||||
|
|
||||||
|
const iconVisible =
|
||||||
|
!menuItemSelectedIcon || typeof menuItemSelectedIcon === 'function' || selected;
|
||||||
|
|
||||||
|
const content = mergedLabel || value;
|
||||||
|
// https://github.com/ant-design/ant-design/issues/26717
|
||||||
|
let optionTitle =
|
||||||
|
typeof content === 'string' || typeof content === 'number'
|
||||||
|
? content.toString()
|
||||||
|
: undefined;
|
||||||
|
if (title !== undefined) {
|
||||||
|
optionTitle = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...otherProps}
|
||||||
|
aria-selected={selected}
|
||||||
|
class={optionClassName}
|
||||||
|
title={optionTitle}
|
||||||
|
onMousemove={() => {
|
||||||
|
if (activeIndex === itemIndex || disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setActive(itemIndex);
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
if (!disabled) {
|
||||||
|
onSelectValue(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<div class={`${optionPrefixCls}-content`}>{content}</div>
|
||||||
|
{isValidElement(menuItemSelectedIcon) || selected}
|
||||||
|
{iconVisible && (
|
||||||
|
<TransBtn
|
||||||
|
class={`${itemPrefixCls}-option-state`}
|
||||||
|
customizeIcon={menuItemSelectedIcon}
|
||||||
|
customizeIconProps={{ isSelected: selected }}
|
||||||
|
>
|
||||||
|
{selected ? '✓' : null}
|
||||||
|
</TransBtn>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</List>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OptionList;
|
|
@ -0,0 +1,144 @@
|
||||||
|
import Trigger from '../vc-trigger';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
import { getSlot } from '../_util/props-util';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import createRef from '../_util/createRef';
|
||||||
|
|
||||||
|
const getBuiltInPlacements = dropdownMatchSelectWidth => {
|
||||||
|
// Enable horizontal overflow auto-adjustment when a custom dropdown width is provided
|
||||||
|
const adjustX = typeof dropdownMatchSelectWidth !== 'number' ? 0 : 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
bottomLeft: {
|
||||||
|
points: ['tl', 'bl'],
|
||||||
|
offset: [0, 4],
|
||||||
|
overflow: {
|
||||||
|
adjustX,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bottomRight: {
|
||||||
|
points: ['tr', 'br'],
|
||||||
|
offset: [0, 4],
|
||||||
|
overflow: {
|
||||||
|
adjustX,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topLeft: {
|
||||||
|
points: ['bl', 'tl'],
|
||||||
|
offset: [0, -4],
|
||||||
|
overflow: {
|
||||||
|
adjustX,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topRight: {
|
||||||
|
points: ['br', 'tr'],
|
||||||
|
offset: [0, -4],
|
||||||
|
overflow: {
|
||||||
|
adjustX,
|
||||||
|
adjustY: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SelectTrigger',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
// onPopupFocus: PropTypes.func,
|
||||||
|
// onPopupScroll: PropTypes.func,
|
||||||
|
dropdownAlign: PropTypes.object,
|
||||||
|
visible: PropTypes.bool,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
dropdownClassName: PropTypes.string,
|
||||||
|
dropdownStyle: PropTypes.object,
|
||||||
|
empty: PropTypes.bool,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
popupClassName: PropTypes.string,
|
||||||
|
// children: PropTypes.any,
|
||||||
|
animation: PropTypes.string,
|
||||||
|
transitionName: PropTypes.string,
|
||||||
|
getPopupContainer: PropTypes.func,
|
||||||
|
dropdownRender: PropTypes.func,
|
||||||
|
containerWidth: PropTypes.number,
|
||||||
|
dropdownMatchSelectWidth: PropTypes.oneOfType([Number, Boolean]).def(true),
|
||||||
|
popupElement: PropTypes.any,
|
||||||
|
direction: PropTypes.string,
|
||||||
|
getTriggerDOMNode: PropTypes.func,
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.popupRef = createRef();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getDropdownTransitionName() {
|
||||||
|
const props = this.$props;
|
||||||
|
let transitionName = props.transitionName;
|
||||||
|
if (!transitionName && props.animation) {
|
||||||
|
transitionName = `${this.getDropdownPrefixCls()}-${props.animation}`;
|
||||||
|
}
|
||||||
|
return transitionName;
|
||||||
|
},
|
||||||
|
getPopupElement() {
|
||||||
|
return this.popupRef.current;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { empty, ...props } = { ...this.$props, ...this.$attrs };
|
||||||
|
const {
|
||||||
|
visible,
|
||||||
|
dropdownAlign,
|
||||||
|
prefixCls,
|
||||||
|
popupElement,
|
||||||
|
dropdownClassName,
|
||||||
|
dropdownStyle,
|
||||||
|
dropdownMatchSelectWidth,
|
||||||
|
containerWidth,
|
||||||
|
dropdownRender,
|
||||||
|
} = props;
|
||||||
|
const dropdownPrefixCls = `${prefixCls}-dropdown`;
|
||||||
|
|
||||||
|
let popupNode = popupElement;
|
||||||
|
if (dropdownRender) {
|
||||||
|
popupNode = dropdownRender({ menuNode: popupElement, props });
|
||||||
|
}
|
||||||
|
|
||||||
|
const builtInPlacements = getBuiltInPlacements(dropdownMatchSelectWidth);
|
||||||
|
const popupStyle = { minWidth: containerWidth, ...dropdownStyle };
|
||||||
|
|
||||||
|
if (typeof dropdownMatchSelectWidth === 'number') {
|
||||||
|
popupStyle.width = `${dropdownMatchSelectWidth}px`;
|
||||||
|
} else if (dropdownMatchSelectWidth) {
|
||||||
|
popupStyle.width = `${containerWidth}px`;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Trigger
|
||||||
|
{...props}
|
||||||
|
showAction={[]}
|
||||||
|
hideAction={[]}
|
||||||
|
popupPlacement={this.direction === 'rtl' ? 'bottomRight' : 'bottomLeft'}
|
||||||
|
popupPlacement="bottomLeft"
|
||||||
|
builtinPlacements={builtInPlacements}
|
||||||
|
prefixCls={dropdownPrefixCls}
|
||||||
|
popupTransitionName={this.getDropdownTransitionName()}
|
||||||
|
onPopupVisibleChange={props.onDropdownVisibleChange}
|
||||||
|
popup={<div ref={this.popupRef}>{popupNode}</div>}
|
||||||
|
popupAlign={dropdownAlign}
|
||||||
|
popupVisible={visible}
|
||||||
|
getPopupContainer={props.getPopupContainer}
|
||||||
|
popupClassName={classNames(dropdownClassName, {
|
||||||
|
[`${dropdownPrefixCls}-empty`]: empty,
|
||||||
|
})}
|
||||||
|
popupStyle={popupStyle}
|
||||||
|
getTriggerDOMNode={this.getTriggerDOMNode}
|
||||||
|
>
|
||||||
|
{getSlot(this)[0]}
|
||||||
|
</Trigger>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
const TransBtn = (
|
||||||
|
_,
|
||||||
|
{ attrs: { class: className, customizeIcon, customizeIconProps, onMousedown, onClick }, slots },
|
||||||
|
) => {
|
||||||
|
let icon;
|
||||||
|
|
||||||
|
if (typeof customizeIcon === 'function') {
|
||||||
|
icon = customizeIcon(customizeIconProps);
|
||||||
|
} else {
|
||||||
|
icon = customizeIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
class={className}
|
||||||
|
onMousedown={event => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (onMousedown) {
|
||||||
|
onMousedown(event);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
userSelect: 'none',
|
||||||
|
WebkitUserSelect: 'none',
|
||||||
|
}}
|
||||||
|
unselectable="on"
|
||||||
|
onClick={onClick}
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
|
{icon !== undefined ? (
|
||||||
|
icon
|
||||||
|
) : (
|
||||||
|
<span class={className.split(/\s+/).map(cls => `${cls}-icon`)}>{slots?.default()}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TransBtn.inheritAttrs = false;
|
||||||
|
|
||||||
|
export default TransBtn;
|
|
@ -0,0 +1,9 @@
|
||||||
|
// based on vc-select 9.2.2
|
||||||
|
import Select from './Select';
|
||||||
|
import Option from './Option';
|
||||||
|
import { SelectPropTypes } from './PropTypes';
|
||||||
|
import OptGroup from './OptGroup';
|
||||||
|
Select.Option = Option;
|
||||||
|
Select.OptGroup = OptGroup;
|
||||||
|
export { Select, Option, OptGroup, SelectPropTypes };
|
||||||
|
export default Select;
|
|
@ -282,7 +282,6 @@ const List = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const { style, class: className } = this.$attrs;
|
|
||||||
const {
|
const {
|
||||||
prefixCls = 'rc-virtual-list',
|
prefixCls = 'rc-virtual-list',
|
||||||
height,
|
height,
|
||||||
|
@ -295,8 +294,10 @@ const List = {
|
||||||
component: Component = 'div',
|
component: Component = 'div',
|
||||||
onScroll,
|
onScroll,
|
||||||
children,
|
children,
|
||||||
|
style,
|
||||||
|
class: className,
|
||||||
...restProps
|
...restProps
|
||||||
} = this.$props;
|
} = { ...this.$props, ...this.$attrs };
|
||||||
const mergedClassName = classNames(prefixCls, className);
|
const mergedClassName = classNames(prefixCls, className);
|
||||||
const { scrollTop, mergedData } = this.state;
|
const { scrollTop, mergedData } = this.state;
|
||||||
const { scrollHeight, offset, start, end } = this.calRes;
|
const { scrollHeight, offset, start, end } = this.calRes;
|
||||||
|
|
Loading…
Reference in New Issue