77 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
| import type { Ref } from 'vue';
 | |
| import { computed } from 'vue';
 | |
| import type { DefaultOptionType, ShowSearchType, InternalFieldNames } from '../Cascader';
 | |
| 
 | |
| export const SEARCH_MARK = '__rc_cascader_search_mark__';
 | |
| 
 | |
| const defaultFilter: ShowSearchType['filter'] = (search, options, { label }) =>
 | |
|   options.some(opt => String(opt[label]).toLowerCase().includes(search.toLowerCase()));
 | |
| 
 | |
| const defaultRender: ShowSearchType['render'] = ({ path, fieldNames }) =>
 | |
|   path.map(opt => opt[fieldNames.label]).join(' / ');
 | |
| 
 | |
| export default (
 | |
|   search: Ref<string>,
 | |
|   options: Ref<DefaultOptionType[]>,
 | |
|   fieldNames: Ref<InternalFieldNames>,
 | |
|   prefixCls: Ref<string>,
 | |
|   config: Ref<ShowSearchType>,
 | |
|   changeOnSelect: Ref<boolean>,
 | |
| ) => {
 | |
|   return computed(() => {
 | |
|     const { filter = defaultFilter, render = defaultRender, limit = 50, sort } = config.value;
 | |
|     const filteredOptions: DefaultOptionType[] = [];
 | |
|     if (!search.value) {
 | |
|       return [];
 | |
|     }
 | |
| 
 | |
|     function dig(list: DefaultOptionType[], pathOptions: DefaultOptionType[]) {
 | |
|       list.forEach(option => {
 | |
|         // Perf saving when `sort` is disabled and `limit` is provided
 | |
|         if (!sort && limit > 0 && filteredOptions.length >= limit) {
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         const connectedPathOptions = [...pathOptions, option];
 | |
|         const children = option[fieldNames.value.children];
 | |
| 
 | |
|         // If current option is filterable
 | |
|         if (
 | |
|           // If is leaf option
 | |
|           !children ||
 | |
|           // If is changeOnSelect
 | |
|           changeOnSelect.value
 | |
|         ) {
 | |
|           if (filter(search.value, connectedPathOptions, { label: fieldNames.value.label })) {
 | |
|             filteredOptions.push({
 | |
|               ...option,
 | |
|               [fieldNames.value.label as 'label']: render({
 | |
|                 inputValue: search.value,
 | |
|                 path: connectedPathOptions,
 | |
|                 prefixCls: prefixCls.value,
 | |
|                 fieldNames: fieldNames.value,
 | |
|               }),
 | |
|               [SEARCH_MARK]: connectedPathOptions,
 | |
|             });
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (children) {
 | |
|           dig(option[fieldNames.value.children] as DefaultOptionType[], connectedPathOptions);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     dig(options.value, []);
 | |
| 
 | |
|     // Do sort
 | |
|     if (sort) {
 | |
|       filteredOptions.sort((a, b) => {
 | |
|         return sort(a[SEARCH_MARK], b[SEARCH_MARK], search.value, fieldNames.value);
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     return limit > 0 ? filteredOptions.slice(0, limit as number) : filteredOptions;
 | |
|   });
 | |
| };
 |