@v-c/select 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/BaseSelect/Polite.cjs +37 -0
- package/dist/BaseSelect/Polite.d.ts +7 -0
- package/dist/BaseSelect/Polite.js +34 -0
- package/dist/BaseSelect/index.cjs +763 -0
- package/dist/BaseSelect/index.d.ts +133 -0
- package/dist/BaseSelect/index.js +759 -0
- package/dist/OptGroup.cjs +5 -0
- package/dist/OptGroup.d.ts +6 -0
- package/dist/OptGroup.js +4 -0
- package/dist/Option.cjs +5 -0
- package/dist/Option.d.ts +8 -0
- package/dist/Option.js +4 -0
- package/dist/OptionList.cjs +255 -0
- package/dist/OptionList.d.ts +17 -0
- package/dist/OptionList.js +249 -0
- package/dist/Select.cjs +833 -0
- package/dist/Select.d.ts +96 -0
- package/dist/Select.js +828 -0
- package/dist/SelectContext.cjs +11 -0
- package/dist/SelectContext.d.ts +32 -0
- package/dist/SelectContext.js +9 -0
- package/dist/SelectInput/Affix.cjs +16 -0
- package/dist/SelectInput/Affix.d.ts +2 -0
- package/dist/SelectInput/Affix.js +13 -0
- package/dist/SelectInput/Content/MultipleContent.cjs +142 -0
- package/dist/SelectInput/Content/MultipleContent.d.ts +3 -0
- package/dist/SelectInput/Content/MultipleContent.js +138 -0
- package/dist/SelectInput/Content/Placeholder.cjs +33 -0
- package/dist/SelectInput/Content/Placeholder.d.ts +5 -0
- package/dist/SelectInput/Content/Placeholder.js +30 -0
- package/dist/SelectInput/Content/SingleContent.cjs +80 -0
- package/dist/SelectInput/Content/SingleContent.d.ts +3 -0
- package/dist/SelectInput/Content/SingleContent.js +77 -0
- package/dist/SelectInput/Content/index.cjs +40 -0
- package/dist/SelectInput/Content/index.d.ts +6 -0
- package/dist/SelectInput/Content/index.js +36 -0
- package/dist/SelectInput/Input.cjs +176 -0
- package/dist/SelectInput/Input.d.ts +22 -0
- package/dist/SelectInput/Input.js +173 -0
- package/dist/SelectInput/context.cjs +11 -0
- package/dist/SelectInput/context.d.ts +5 -0
- package/dist/SelectInput/context.js +9 -0
- package/dist/SelectInput/index.cjs +330 -0
- package/dist/SelectInput/index.d.ts +44 -0
- package/dist/SelectInput/index.js +325 -0
- package/dist/SelectTrigger.cjs +189 -0
- package/dist/SelectTrigger.d.ts +26 -0
- package/dist/SelectTrigger.js +185 -0
- package/dist/TransBtn.cjs +69 -0
- package/dist/TransBtn.d.ts +22 -0
- package/dist/TransBtn.js +66 -0
- package/dist/_virtual/rolldown_runtime.cjs +21 -0
- package/dist/hooks/index.cjs +23 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/index.js +12 -0
- package/dist/hooks/useAllowClear.cjs +17 -0
- package/dist/hooks/useAllowClear.d.ts +9 -0
- package/dist/hooks/useAllowClear.js +16 -0
- package/dist/hooks/useBaseProps.cjs +12 -0
- package/dist/hooks/useBaseProps.d.ts +10 -0
- package/dist/hooks/useBaseProps.js +9 -0
- package/dist/hooks/useCache.cjs +36 -0
- package/dist/hooks/useCache.d.ts +7 -0
- package/dist/hooks/useCache.js +34 -0
- package/dist/hooks/useComponents.cjs +15 -0
- package/dist/hooks/useComponents.d.ts +8 -0
- package/dist/hooks/useComponents.js +13 -0
- package/dist/hooks/useFilterOptions.cjs +39 -0
- package/dist/hooks/useFilterOptions.d.ts +3 -0
- package/dist/hooks/useFilterOptions.js +37 -0
- package/dist/hooks/useLock.cjs +26 -0
- package/dist/hooks/useLock.d.ts +1 -0
- package/dist/hooks/useLock.js +24 -0
- package/dist/hooks/useOpen.cjs +58 -0
- package/dist/hooks/useOpen.d.ts +19 -0
- package/dist/hooks/useOpen.js +56 -0
- package/dist/hooks/useOptions.cjs +38 -0
- package/dist/hooks/useOptions.d.ts +13 -0
- package/dist/hooks/useOptions.js +36 -0
- package/dist/hooks/useRefFunc.cjs +12 -0
- package/dist/hooks/useRefFunc.d.ts +6 -0
- package/dist/hooks/useRefFunc.js +10 -0
- package/dist/hooks/useSearchConfig.cjs +21 -0
- package/dist/hooks/useSearchConfig.d.ts +11 -0
- package/dist/hooks/useSearchConfig.js +19 -0
- package/dist/hooks/useSelectTriggerControl.cjs +18 -0
- package/dist/hooks/useSelectTriggerControl.d.ts +2 -0
- package/dist/hooks/useSelectTriggerControl.js +16 -0
- package/dist/index.cjs +16 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +8 -0
- package/dist/interface.cjs +0 -0
- package/dist/interface.d.ts +23 -0
- package/dist/interface.js +0 -0
- package/dist/utils/commonUtil.cjs +37 -0
- package/dist/utils/commonUtil.d.ts +12 -0
- package/dist/utils/commonUtil.js +30 -0
- package/dist/utils/keyUtil.cjs +36 -0
- package/dist/utils/keyUtil.d.ts +2 -0
- package/dist/utils/keyUtil.js +34 -0
- package/dist/utils/legacyUtil.cjs +32 -0
- package/dist/utils/legacyUtil.d.ts +3 -0
- package/dist/utils/legacyUtil.js +31 -0
- package/dist/utils/platformUtil.cjs +5 -0
- package/dist/utils/platformUtil.d.ts +1 -0
- package/dist/utils/platformUtil.js +5 -0
- package/dist/utils/valueUtil.cjs +79 -0
- package/dist/utils/valueUtil.d.ts +18 -0
- package/dist/utils/valueUtil.js +75 -0
- package/package.json +43 -0
package/dist/OptGroup.js
ADDED
package/dist/Option.cjs
ADDED
package/dist/Option.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FunctionalComponent } from 'vue';
|
|
2
|
+
import { DefaultOptionType } from './Select.tsx';
|
|
3
|
+
export interface OptionProps extends Omit<DefaultOptionType, 'label'> {
|
|
4
|
+
/** Save for customize data */
|
|
5
|
+
[prop: string]: any;
|
|
6
|
+
}
|
|
7
|
+
declare const Option: FunctionalComponent<OptionProps>;
|
|
8
|
+
export default Option;
|
package/dist/Option.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
|
|
3
|
+
const require_useBaseProps = require("./hooks/useBaseProps.cjs");
|
|
4
|
+
const require_SelectContext = require("./SelectContext.cjs");
|
|
5
|
+
const require_TransBtn = require("./TransBtn.cjs");
|
|
6
|
+
const require_platformUtil = require("./utils/platformUtil.cjs");
|
|
7
|
+
const require_valueUtil = require("./utils/valueUtil.cjs");
|
|
8
|
+
let vue = require("vue");
|
|
9
|
+
let __v_c_util = require("@v-c/util");
|
|
10
|
+
let __v_c_util_dist_KeyCode = require("@v-c/util/dist/KeyCode");
|
|
11
|
+
__v_c_util_dist_KeyCode = require_rolldown_runtime.__toESM(__v_c_util_dist_KeyCode);
|
|
12
|
+
let __v_c_util_dist_pickAttrs = require("@v-c/util/dist/pickAttrs");
|
|
13
|
+
__v_c_util_dist_pickAttrs = require_rolldown_runtime.__toESM(__v_c_util_dist_pickAttrs);
|
|
14
|
+
let __v_c_virtual_list = require("@v-c/virtual-list");
|
|
15
|
+
__v_c_virtual_list = require_rolldown_runtime.__toESM(__v_c_virtual_list);
|
|
16
|
+
function isTitleType(content) {
|
|
17
|
+
return typeof content === "string" || typeof content === "number";
|
|
18
|
+
}
|
|
19
|
+
var OptionList = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
20
|
+
name: "OptionList",
|
|
21
|
+
inheritAttrs: false,
|
|
22
|
+
setup(_, { expose }) {
|
|
23
|
+
const baseProps = require_useBaseProps.default();
|
|
24
|
+
const context = require_SelectContext.useSelectContext();
|
|
25
|
+
const itemPrefixCls = (0, vue.computed)(() => `${baseProps.value?.prefixCls}-item`);
|
|
26
|
+
const memoFlattenOptions = (0, vue.computed)(() => {
|
|
27
|
+
if (!baseProps.value?.open) return context.value?.flattenOptions || [];
|
|
28
|
+
return context.value?.flattenOptions || [];
|
|
29
|
+
});
|
|
30
|
+
const listRef = (0, vue.shallowRef)(null);
|
|
31
|
+
const overMaxCount = (0, vue.computed)(() => {
|
|
32
|
+
const { maxCount, rawValues } = context.value || {};
|
|
33
|
+
return !!(baseProps.value?.multiple && require_valueUtil.isValidCount(maxCount) && rawValues && rawValues.size >= maxCount);
|
|
34
|
+
});
|
|
35
|
+
const onListMouseDown = (event) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
};
|
|
38
|
+
const scrollIntoView = (args) => {
|
|
39
|
+
listRef.value?.scrollTo(typeof args === "number" ? { index: args } : args);
|
|
40
|
+
};
|
|
41
|
+
const isSelected = (value) => {
|
|
42
|
+
if (baseProps.value?.mode === "combobox") return false;
|
|
43
|
+
return context.value?.rawValues?.has(value) || false;
|
|
44
|
+
};
|
|
45
|
+
const getEnabledActiveIndex = (index, offset = 1) => {
|
|
46
|
+
const len = memoFlattenOptions.value.length;
|
|
47
|
+
for (let i = 0; i < len; i += 1) {
|
|
48
|
+
const current = (index + i * offset + len) % len;
|
|
49
|
+
const { group, data } = memoFlattenOptions.value[current] || {};
|
|
50
|
+
if (!group && !data?.disabled && (isSelected(data?.value) || !overMaxCount.value)) return current;
|
|
51
|
+
}
|
|
52
|
+
return -1;
|
|
53
|
+
};
|
|
54
|
+
const activeIndex = (0, vue.shallowRef)(-1);
|
|
55
|
+
const setActive = (index, fromKeyboard = false) => {
|
|
56
|
+
activeIndex.value = index;
|
|
57
|
+
const info = { source: fromKeyboard ? "keyboard" : "mouse" };
|
|
58
|
+
const flattenItem = memoFlattenOptions.value[index];
|
|
59
|
+
if (!flattenItem) {
|
|
60
|
+
context.value?.onActiveValue?.(null, -1, info);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
context.value?.onActiveValue?.(flattenItem.value, index, info);
|
|
64
|
+
};
|
|
65
|
+
(0, vue.watch)([() => memoFlattenOptions.value.length, () => baseProps.value?.searchValue], () => {
|
|
66
|
+
setActive(context.value?.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
|
|
67
|
+
}, { immediate: true });
|
|
68
|
+
const isAriaSelected = (value) => {
|
|
69
|
+
if (baseProps.value?.mode === "combobox") return String(value).toLowerCase() === (baseProps.value?.searchValue || "").toLowerCase();
|
|
70
|
+
return context.value?.rawValues?.has(value) || false;
|
|
71
|
+
};
|
|
72
|
+
(0, vue.watch)([() => baseProps.value?.open, () => baseProps.value?.searchValue], () => {
|
|
73
|
+
let timeoutId;
|
|
74
|
+
const rawValues = context.value?.rawValues;
|
|
75
|
+
if (!baseProps.value?.multiple && baseProps.value?.open && rawValues?.size === 1) {
|
|
76
|
+
const value = Array.from(rawValues)[0];
|
|
77
|
+
const searchValue = baseProps.value?.searchValue;
|
|
78
|
+
const index = memoFlattenOptions.value.findIndex(({ data }) => searchValue ? String(data.value).startsWith(searchValue) : data.value === value);
|
|
79
|
+
if (index !== -1) {
|
|
80
|
+
setActive(index);
|
|
81
|
+
timeoutId = setTimeout(() => {
|
|
82
|
+
scrollIntoView(index);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (baseProps.value?.open) listRef.value?.scrollTo(void 0);
|
|
87
|
+
return () => {
|
|
88
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
const onSelectValue = (value) => {
|
|
92
|
+
if (value !== void 0) context.value?.onSelect?.(value, { selected: !context.value?.rawValues?.has(value) });
|
|
93
|
+
if (!baseProps.value?.multiple) baseProps.value?.toggleOpen?.(false);
|
|
94
|
+
};
|
|
95
|
+
const onKeyDown = (event) => {
|
|
96
|
+
const { which, ctrlKey } = event;
|
|
97
|
+
switch (which) {
|
|
98
|
+
case __v_c_util_dist_KeyCode.default.N:
|
|
99
|
+
case __v_c_util_dist_KeyCode.default.P:
|
|
100
|
+
case __v_c_util_dist_KeyCode.default.UP:
|
|
101
|
+
case __v_c_util_dist_KeyCode.default.DOWN: {
|
|
102
|
+
let offset = 0;
|
|
103
|
+
if (which === __v_c_util_dist_KeyCode.default.UP) offset = -1;
|
|
104
|
+
else if (which === __v_c_util_dist_KeyCode.default.DOWN) offset = 1;
|
|
105
|
+
else if (require_platformUtil.isPlatformMac() && ctrlKey) {
|
|
106
|
+
if (which === __v_c_util_dist_KeyCode.default.N) offset = 1;
|
|
107
|
+
else if (which === __v_c_util_dist_KeyCode.default.P) offset = -1;
|
|
108
|
+
}
|
|
109
|
+
if (offset !== 0) {
|
|
110
|
+
const nextActiveIndex = getEnabledActiveIndex(activeIndex.value + offset, offset);
|
|
111
|
+
scrollIntoView(nextActiveIndex);
|
|
112
|
+
setActive(nextActiveIndex, true);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case __v_c_util_dist_KeyCode.default.TAB:
|
|
117
|
+
case __v_c_util_dist_KeyCode.default.ENTER: {
|
|
118
|
+
const item = memoFlattenOptions.value[activeIndex.value];
|
|
119
|
+
if (!item || item.data.disabled) {
|
|
120
|
+
onSelectValue(void 0);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (!overMaxCount.value || context.value?.rawValues?.has(item.value)) onSelectValue(item.value);
|
|
124
|
+
else onSelectValue(void 0);
|
|
125
|
+
if (baseProps.value?.open) event.preventDefault();
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case __v_c_util_dist_KeyCode.default.ESC:
|
|
129
|
+
baseProps.value?.toggleOpen?.(false);
|
|
130
|
+
if (baseProps.value?.open) event.stopPropagation();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const onKeyUp = () => {};
|
|
134
|
+
expose({
|
|
135
|
+
onKeyDown,
|
|
136
|
+
onKeyUp,
|
|
137
|
+
scrollTo: (index) => {
|
|
138
|
+
scrollIntoView(index);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return () => {
|
|
142
|
+
const { id, notFoundContent, onPopupScroll } = baseProps.value || {};
|
|
143
|
+
const { menuItemSelectedIcon, fieldNames, virtual, direction, listHeight, listItemHeight, optionRender, classNames: contextClassNames, styles: contextStyles } = context.value || {};
|
|
144
|
+
if (memoFlattenOptions.value.length === 0) return (0, vue.createVNode)("div", {
|
|
145
|
+
"role": "listbox",
|
|
146
|
+
"id": `${id}_list`,
|
|
147
|
+
"class": `${itemPrefixCls.value}-empty`,
|
|
148
|
+
"onMousedown": onListMouseDown
|
|
149
|
+
}, [notFoundContent]);
|
|
150
|
+
const omitFieldNameList = Object.keys(fieldNames || {}).map((key) => fieldNames?.[key]);
|
|
151
|
+
const getLabel = (item) => item.label;
|
|
152
|
+
function getItemAriaProps(item, index) {
|
|
153
|
+
const { group } = item;
|
|
154
|
+
return {
|
|
155
|
+
role: group ? "presentation" : "option",
|
|
156
|
+
id: `${id}_list_${index}`
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const renderItem = (index) => {
|
|
160
|
+
const item = memoFlattenOptions.value[index];
|
|
161
|
+
if (!item) return null;
|
|
162
|
+
const itemData = item.data || {};
|
|
163
|
+
const { value } = itemData;
|
|
164
|
+
const { group } = item;
|
|
165
|
+
const attrs = (0, __v_c_util_dist_pickAttrs.default)(itemData, true);
|
|
166
|
+
const mergedLabel = getLabel(item);
|
|
167
|
+
return item ? (0, vue.createVNode)("div", (0, vue.mergeProps)({ "aria-label": typeof mergedLabel === "string" && !group ? mergedLabel : void 0 }, attrs, { "key": index }, getItemAriaProps(item, index), { "aria-selected": isAriaSelected(value) }), [value]) : null;
|
|
168
|
+
};
|
|
169
|
+
const a11yProps = {
|
|
170
|
+
role: "listbox",
|
|
171
|
+
id: `${id}_list`
|
|
172
|
+
};
|
|
173
|
+
return (0, vue.createVNode)(vue.Fragment, null, [virtual && (0, vue.createVNode)("div", (0, vue.mergeProps)(a11yProps, { "style": {
|
|
174
|
+
height: 0,
|
|
175
|
+
width: 0,
|
|
176
|
+
overflow: "hidden"
|
|
177
|
+
} }), [
|
|
178
|
+
renderItem(activeIndex.value - 1),
|
|
179
|
+
renderItem(activeIndex.value),
|
|
180
|
+
renderItem(activeIndex.value + 1)
|
|
181
|
+
]), (0, vue.createVNode)(__v_c_virtual_list.default, (0, vue.mergeProps)({
|
|
182
|
+
"itemKey": "key",
|
|
183
|
+
"ref": (el) => {
|
|
184
|
+
listRef.value = el;
|
|
185
|
+
},
|
|
186
|
+
"data": memoFlattenOptions.value,
|
|
187
|
+
"height": listHeight,
|
|
188
|
+
"itemHeight": listItemHeight,
|
|
189
|
+
"fullHeight": false
|
|
190
|
+
}, { onMousedown: onListMouseDown }, {
|
|
191
|
+
"onScroll": onPopupScroll,
|
|
192
|
+
"virtual": virtual,
|
|
193
|
+
"direction": direction,
|
|
194
|
+
"innerProps": virtual ? void 0 : a11yProps,
|
|
195
|
+
"class": contextClassNames?.popup?.list,
|
|
196
|
+
"style": contextStyles?.popup?.list
|
|
197
|
+
}), { default: ({ item, index: itemIndex }) => {
|
|
198
|
+
const { group, groupOption, data, label, value } = item;
|
|
199
|
+
const { key } = data;
|
|
200
|
+
if (group) {
|
|
201
|
+
const groupTitle = data.title ?? (isTitleType(label) ? label.toString() : void 0);
|
|
202
|
+
return (0, vue.createVNode)("div", {
|
|
203
|
+
"class": (0, __v_c_util.clsx)(itemPrefixCls.value, `${itemPrefixCls.value}-group`, data.className),
|
|
204
|
+
"title": groupTitle
|
|
205
|
+
}, [label !== void 0 ? label : key]);
|
|
206
|
+
}
|
|
207
|
+
const { disabled, title, children, style, className,...otherProps } = data;
|
|
208
|
+
const passedProps = {};
|
|
209
|
+
Object.keys(otherProps).forEach((propKey) => {
|
|
210
|
+
if (!omitFieldNameList.includes(propKey)) passedProps[propKey] = otherProps[propKey];
|
|
211
|
+
});
|
|
212
|
+
const selected = isSelected(value);
|
|
213
|
+
const mergedDisabled = disabled || !selected && overMaxCount.value;
|
|
214
|
+
const optionPrefixCls = `${itemPrefixCls.value}-option`;
|
|
215
|
+
const optionClassName = (0, __v_c_util.clsx)(itemPrefixCls.value, optionPrefixCls, className, contextClassNames?.popup?.listItem, {
|
|
216
|
+
[`${optionPrefixCls}-grouped`]: groupOption,
|
|
217
|
+
[`${optionPrefixCls}-active`]: activeIndex.value === itemIndex && !mergedDisabled,
|
|
218
|
+
[`${optionPrefixCls}-disabled`]: mergedDisabled,
|
|
219
|
+
[`${optionPrefixCls}-selected`]: selected
|
|
220
|
+
});
|
|
221
|
+
const mergedLabel = getLabel(item);
|
|
222
|
+
const iconVisible = !menuItemSelectedIcon || typeof menuItemSelectedIcon === "function" || selected;
|
|
223
|
+
const content = typeof mergedLabel === "number" ? mergedLabel : mergedLabel || value;
|
|
224
|
+
let optionTitle = isTitleType(content) ? content.toString() : void 0;
|
|
225
|
+
if (title !== void 0) optionTitle = title;
|
|
226
|
+
return (0, vue.createVNode)("div", (0, vue.mergeProps)((0, __v_c_util_dist_pickAttrs.default)(passedProps), !virtual ? getItemAriaProps(item, itemIndex) : {}, {
|
|
227
|
+
"aria-selected": virtual ? void 0 : isAriaSelected(value),
|
|
228
|
+
"class": optionClassName,
|
|
229
|
+
"title": optionTitle,
|
|
230
|
+
"onMousemove": () => {
|
|
231
|
+
if (activeIndex.value === itemIndex || mergedDisabled) return;
|
|
232
|
+
setActive(itemIndex);
|
|
233
|
+
},
|
|
234
|
+
"onClick": () => {
|
|
235
|
+
if (!mergedDisabled) onSelectValue(value);
|
|
236
|
+
},
|
|
237
|
+
"style": {
|
|
238
|
+
...contextStyles?.popup?.listItem,
|
|
239
|
+
...style
|
|
240
|
+
}
|
|
241
|
+
}), [(0, vue.createVNode)("div", { "class": `${optionPrefixCls}-content` }, [typeof optionRender === "function" ? optionRender(item, { index: itemIndex }) : content]), iconVisible && (0, vue.createVNode)(require_TransBtn.default, {
|
|
242
|
+
"className": `${itemPrefixCls.value}-option-state`,
|
|
243
|
+
"customizeIcon": menuItemSelectedIcon,
|
|
244
|
+
"customizeIconProps": {
|
|
245
|
+
value,
|
|
246
|
+
disabled: mergedDisabled,
|
|
247
|
+
isSelected: selected
|
|
248
|
+
}
|
|
249
|
+
}, { default: () => [selected ? "✓" : null] })]);
|
|
250
|
+
} })]);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
var OptionList_default = OptionList;
|
|
255
|
+
exports.default = OptionList_default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ScrollConfig {
|
|
2
|
+
index?: number;
|
|
3
|
+
key?: string | number;
|
|
4
|
+
align?: 'top' | 'bottom' | 'auto';
|
|
5
|
+
offset?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface RefOptionListProps {
|
|
8
|
+
onKeyDown: (event: KeyboardEvent) => void;
|
|
9
|
+
onKeyUp: (event: KeyboardEvent) => void;
|
|
10
|
+
scrollTo?: (args: number | ScrollConfig) => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Using virtual list of option display.
|
|
14
|
+
* Will fallback to dom if use customize render.
|
|
15
|
+
*/
|
|
16
|
+
declare const OptionList: import('vue').DefineComponent<{}, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
17
|
+
export default OptionList;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import useBaseProps from "./hooks/useBaseProps.js";
|
|
2
|
+
import { useSelectContext } from "./SelectContext.js";
|
|
3
|
+
import TransBtn_default from "./TransBtn.js";
|
|
4
|
+
import { isPlatformMac } from "./utils/platformUtil.js";
|
|
5
|
+
import { isValidCount } from "./utils/valueUtil.js";
|
|
6
|
+
import { Fragment, computed, createVNode, defineComponent, mergeProps, shallowRef, watch } from "vue";
|
|
7
|
+
import { clsx } from "@v-c/util";
|
|
8
|
+
import KeyCode from "@v-c/util/dist/KeyCode";
|
|
9
|
+
import pickAttrs from "@v-c/util/dist/pickAttrs";
|
|
10
|
+
import List from "@v-c/virtual-list";
|
|
11
|
+
function isTitleType(content) {
|
|
12
|
+
return typeof content === "string" || typeof content === "number";
|
|
13
|
+
}
|
|
14
|
+
var OptionList_default = /* @__PURE__ */ defineComponent({
|
|
15
|
+
name: "OptionList",
|
|
16
|
+
inheritAttrs: false,
|
|
17
|
+
setup(_, { expose }) {
|
|
18
|
+
const baseProps = useBaseProps();
|
|
19
|
+
const context = useSelectContext();
|
|
20
|
+
const itemPrefixCls = computed(() => `${baseProps.value?.prefixCls}-item`);
|
|
21
|
+
const memoFlattenOptions = computed(() => {
|
|
22
|
+
if (!baseProps.value?.open) return context.value?.flattenOptions || [];
|
|
23
|
+
return context.value?.flattenOptions || [];
|
|
24
|
+
});
|
|
25
|
+
const listRef = shallowRef(null);
|
|
26
|
+
const overMaxCount = computed(() => {
|
|
27
|
+
const { maxCount, rawValues } = context.value || {};
|
|
28
|
+
return !!(baseProps.value?.multiple && isValidCount(maxCount) && rawValues && rawValues.size >= maxCount);
|
|
29
|
+
});
|
|
30
|
+
const onListMouseDown = (event) => {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
};
|
|
33
|
+
const scrollIntoView = (args) => {
|
|
34
|
+
listRef.value?.scrollTo(typeof args === "number" ? { index: args } : args);
|
|
35
|
+
};
|
|
36
|
+
const isSelected = (value) => {
|
|
37
|
+
if (baseProps.value?.mode === "combobox") return false;
|
|
38
|
+
return context.value?.rawValues?.has(value) || false;
|
|
39
|
+
};
|
|
40
|
+
const getEnabledActiveIndex = (index, offset = 1) => {
|
|
41
|
+
const len = memoFlattenOptions.value.length;
|
|
42
|
+
for (let i = 0; i < len; i += 1) {
|
|
43
|
+
const current = (index + i * offset + len) % len;
|
|
44
|
+
const { group, data } = memoFlattenOptions.value[current] || {};
|
|
45
|
+
if (!group && !data?.disabled && (isSelected(data?.value) || !overMaxCount.value)) return current;
|
|
46
|
+
}
|
|
47
|
+
return -1;
|
|
48
|
+
};
|
|
49
|
+
const activeIndex = shallowRef(-1);
|
|
50
|
+
const setActive = (index, fromKeyboard = false) => {
|
|
51
|
+
activeIndex.value = index;
|
|
52
|
+
const info = { source: fromKeyboard ? "keyboard" : "mouse" };
|
|
53
|
+
const flattenItem = memoFlattenOptions.value[index];
|
|
54
|
+
if (!flattenItem) {
|
|
55
|
+
context.value?.onActiveValue?.(null, -1, info);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
context.value?.onActiveValue?.(flattenItem.value, index, info);
|
|
59
|
+
};
|
|
60
|
+
watch([() => memoFlattenOptions.value.length, () => baseProps.value?.searchValue], () => {
|
|
61
|
+
setActive(context.value?.defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
|
|
62
|
+
}, { immediate: true });
|
|
63
|
+
const isAriaSelected = (value) => {
|
|
64
|
+
if (baseProps.value?.mode === "combobox") return String(value).toLowerCase() === (baseProps.value?.searchValue || "").toLowerCase();
|
|
65
|
+
return context.value?.rawValues?.has(value) || false;
|
|
66
|
+
};
|
|
67
|
+
watch([() => baseProps.value?.open, () => baseProps.value?.searchValue], () => {
|
|
68
|
+
let timeoutId;
|
|
69
|
+
const rawValues = context.value?.rawValues;
|
|
70
|
+
if (!baseProps.value?.multiple && baseProps.value?.open && rawValues?.size === 1) {
|
|
71
|
+
const value = Array.from(rawValues)[0];
|
|
72
|
+
const searchValue = baseProps.value?.searchValue;
|
|
73
|
+
const index = memoFlattenOptions.value.findIndex(({ data }) => searchValue ? String(data.value).startsWith(searchValue) : data.value === value);
|
|
74
|
+
if (index !== -1) {
|
|
75
|
+
setActive(index);
|
|
76
|
+
timeoutId = setTimeout(() => {
|
|
77
|
+
scrollIntoView(index);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (baseProps.value?.open) listRef.value?.scrollTo(void 0);
|
|
82
|
+
return () => {
|
|
83
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
const onSelectValue = (value) => {
|
|
87
|
+
if (value !== void 0) context.value?.onSelect?.(value, { selected: !context.value?.rawValues?.has(value) });
|
|
88
|
+
if (!baseProps.value?.multiple) baseProps.value?.toggleOpen?.(false);
|
|
89
|
+
};
|
|
90
|
+
const onKeyDown = (event) => {
|
|
91
|
+
const { which, ctrlKey } = event;
|
|
92
|
+
switch (which) {
|
|
93
|
+
case KeyCode.N:
|
|
94
|
+
case KeyCode.P:
|
|
95
|
+
case KeyCode.UP:
|
|
96
|
+
case KeyCode.DOWN: {
|
|
97
|
+
let offset = 0;
|
|
98
|
+
if (which === KeyCode.UP) offset = -1;
|
|
99
|
+
else if (which === KeyCode.DOWN) offset = 1;
|
|
100
|
+
else if (isPlatformMac() && ctrlKey) {
|
|
101
|
+
if (which === KeyCode.N) offset = 1;
|
|
102
|
+
else if (which === KeyCode.P) offset = -1;
|
|
103
|
+
}
|
|
104
|
+
if (offset !== 0) {
|
|
105
|
+
const nextActiveIndex = getEnabledActiveIndex(activeIndex.value + offset, offset);
|
|
106
|
+
scrollIntoView(nextActiveIndex);
|
|
107
|
+
setActive(nextActiveIndex, true);
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case KeyCode.TAB:
|
|
112
|
+
case KeyCode.ENTER: {
|
|
113
|
+
const item = memoFlattenOptions.value[activeIndex.value];
|
|
114
|
+
if (!item || item.data.disabled) {
|
|
115
|
+
onSelectValue(void 0);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!overMaxCount.value || context.value?.rawValues?.has(item.value)) onSelectValue(item.value);
|
|
119
|
+
else onSelectValue(void 0);
|
|
120
|
+
if (baseProps.value?.open) event.preventDefault();
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case KeyCode.ESC:
|
|
124
|
+
baseProps.value?.toggleOpen?.(false);
|
|
125
|
+
if (baseProps.value?.open) event.stopPropagation();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const onKeyUp = () => {};
|
|
129
|
+
expose({
|
|
130
|
+
onKeyDown,
|
|
131
|
+
onKeyUp,
|
|
132
|
+
scrollTo: (index) => {
|
|
133
|
+
scrollIntoView(index);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return () => {
|
|
137
|
+
const { id, notFoundContent, onPopupScroll } = baseProps.value || {};
|
|
138
|
+
const { menuItemSelectedIcon, fieldNames, virtual, direction, listHeight, listItemHeight, optionRender, classNames: contextClassNames, styles: contextStyles } = context.value || {};
|
|
139
|
+
if (memoFlattenOptions.value.length === 0) return createVNode("div", {
|
|
140
|
+
"role": "listbox",
|
|
141
|
+
"id": `${id}_list`,
|
|
142
|
+
"class": `${itemPrefixCls.value}-empty`,
|
|
143
|
+
"onMousedown": onListMouseDown
|
|
144
|
+
}, [notFoundContent]);
|
|
145
|
+
const omitFieldNameList = Object.keys(fieldNames || {}).map((key) => fieldNames?.[key]);
|
|
146
|
+
const getLabel = (item) => item.label;
|
|
147
|
+
function getItemAriaProps(item, index) {
|
|
148
|
+
const { group } = item;
|
|
149
|
+
return {
|
|
150
|
+
role: group ? "presentation" : "option",
|
|
151
|
+
id: `${id}_list_${index}`
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const renderItem = (index) => {
|
|
155
|
+
const item = memoFlattenOptions.value[index];
|
|
156
|
+
if (!item) return null;
|
|
157
|
+
const itemData = item.data || {};
|
|
158
|
+
const { value } = itemData;
|
|
159
|
+
const { group } = item;
|
|
160
|
+
const attrs = pickAttrs(itemData, true);
|
|
161
|
+
const mergedLabel = getLabel(item);
|
|
162
|
+
return item ? createVNode("div", mergeProps({ "aria-label": typeof mergedLabel === "string" && !group ? mergedLabel : void 0 }, attrs, { "key": index }, getItemAriaProps(item, index), { "aria-selected": isAriaSelected(value) }), [value]) : null;
|
|
163
|
+
};
|
|
164
|
+
const a11yProps = {
|
|
165
|
+
role: "listbox",
|
|
166
|
+
id: `${id}_list`
|
|
167
|
+
};
|
|
168
|
+
return createVNode(Fragment, null, [virtual && createVNode("div", mergeProps(a11yProps, { "style": {
|
|
169
|
+
height: 0,
|
|
170
|
+
width: 0,
|
|
171
|
+
overflow: "hidden"
|
|
172
|
+
} }), [
|
|
173
|
+
renderItem(activeIndex.value - 1),
|
|
174
|
+
renderItem(activeIndex.value),
|
|
175
|
+
renderItem(activeIndex.value + 1)
|
|
176
|
+
]), createVNode(List, mergeProps({
|
|
177
|
+
"itemKey": "key",
|
|
178
|
+
"ref": (el) => {
|
|
179
|
+
listRef.value = el;
|
|
180
|
+
},
|
|
181
|
+
"data": memoFlattenOptions.value,
|
|
182
|
+
"height": listHeight,
|
|
183
|
+
"itemHeight": listItemHeight,
|
|
184
|
+
"fullHeight": false
|
|
185
|
+
}, { onMousedown: onListMouseDown }, {
|
|
186
|
+
"onScroll": onPopupScroll,
|
|
187
|
+
"virtual": virtual,
|
|
188
|
+
"direction": direction,
|
|
189
|
+
"innerProps": virtual ? void 0 : a11yProps,
|
|
190
|
+
"class": contextClassNames?.popup?.list,
|
|
191
|
+
"style": contextStyles?.popup?.list
|
|
192
|
+
}), { default: ({ item, index: itemIndex }) => {
|
|
193
|
+
const { group, groupOption, data, label, value } = item;
|
|
194
|
+
const { key } = data;
|
|
195
|
+
if (group) {
|
|
196
|
+
const groupTitle = data.title ?? (isTitleType(label) ? label.toString() : void 0);
|
|
197
|
+
return createVNode("div", {
|
|
198
|
+
"class": clsx(itemPrefixCls.value, `${itemPrefixCls.value}-group`, data.className),
|
|
199
|
+
"title": groupTitle
|
|
200
|
+
}, [label !== void 0 ? label : key]);
|
|
201
|
+
}
|
|
202
|
+
const { disabled, title, children, style, className,...otherProps } = data;
|
|
203
|
+
const passedProps = {};
|
|
204
|
+
Object.keys(otherProps).forEach((propKey) => {
|
|
205
|
+
if (!omitFieldNameList.includes(propKey)) passedProps[propKey] = otherProps[propKey];
|
|
206
|
+
});
|
|
207
|
+
const selected = isSelected(value);
|
|
208
|
+
const mergedDisabled = disabled || !selected && overMaxCount.value;
|
|
209
|
+
const optionPrefixCls = `${itemPrefixCls.value}-option`;
|
|
210
|
+
const optionClassName = clsx(itemPrefixCls.value, optionPrefixCls, className, contextClassNames?.popup?.listItem, {
|
|
211
|
+
[`${optionPrefixCls}-grouped`]: groupOption,
|
|
212
|
+
[`${optionPrefixCls}-active`]: activeIndex.value === itemIndex && !mergedDisabled,
|
|
213
|
+
[`${optionPrefixCls}-disabled`]: mergedDisabled,
|
|
214
|
+
[`${optionPrefixCls}-selected`]: selected
|
|
215
|
+
});
|
|
216
|
+
const mergedLabel = getLabel(item);
|
|
217
|
+
const iconVisible = !menuItemSelectedIcon || typeof menuItemSelectedIcon === "function" || selected;
|
|
218
|
+
const content = typeof mergedLabel === "number" ? mergedLabel : mergedLabel || value;
|
|
219
|
+
let optionTitle = isTitleType(content) ? content.toString() : void 0;
|
|
220
|
+
if (title !== void 0) optionTitle = title;
|
|
221
|
+
return createVNode("div", mergeProps(pickAttrs(passedProps), !virtual ? getItemAriaProps(item, itemIndex) : {}, {
|
|
222
|
+
"aria-selected": virtual ? void 0 : isAriaSelected(value),
|
|
223
|
+
"class": optionClassName,
|
|
224
|
+
"title": optionTitle,
|
|
225
|
+
"onMousemove": () => {
|
|
226
|
+
if (activeIndex.value === itemIndex || mergedDisabled) return;
|
|
227
|
+
setActive(itemIndex);
|
|
228
|
+
},
|
|
229
|
+
"onClick": () => {
|
|
230
|
+
if (!mergedDisabled) onSelectValue(value);
|
|
231
|
+
},
|
|
232
|
+
"style": {
|
|
233
|
+
...contextStyles?.popup?.listItem,
|
|
234
|
+
...style
|
|
235
|
+
}
|
|
236
|
+
}), [createVNode("div", { "class": `${optionPrefixCls}-content` }, [typeof optionRender === "function" ? optionRender(item, { index: itemIndex }) : content]), iconVisible && createVNode(TransBtn_default, {
|
|
237
|
+
"className": `${itemPrefixCls.value}-option-state`,
|
|
238
|
+
"customizeIcon": menuItemSelectedIcon,
|
|
239
|
+
"customizeIconProps": {
|
|
240
|
+
value,
|
|
241
|
+
disabled: mergedDisabled,
|
|
242
|
+
isSelected: selected
|
|
243
|
+
}
|
|
244
|
+
}, { default: () => [selected ? "✓" : null] })]);
|
|
245
|
+
} })]);
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
export { OptionList_default as default };
|