diff --git a/.changeset/clean-grapes-serve.md b/.changeset/clean-grapes-serve.md new file mode 100644 index 000000000..33a610cf5 --- /dev/null +++ b/.changeset/clean-grapes-serve.md @@ -0,0 +1,7 @@ +--- +"@hera/plugin-rental": patch +"@nocobase/client": patch +"@nocobase/utils": patch +--- + +support fuzzy search in cascader diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx index c163fc702..e174bca60 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx @@ -1,17 +1,24 @@ import { ArrayItems, FormItem } from '@formily/antd-v5'; -import { createForm, onFormValuesChange } from '@nocobase/schema'; -import { FormProvider, connect, createSchemaField, observer, useField, useFieldSchema } from '@nocobase/schema'; -import { uid } from '@nocobase/schema'; -import { Input, Space, Spin, Tag } from 'antd'; -import dayjs from 'dayjs'; +import { + FormProvider, + connect, + createForm, + createSchemaField, + observer, + onFormValuesChange, + uid, + useField, + useFieldSchema, +} from '@nocobase/schema'; +import { fuzzysearch } from '@nocobase/utils/client'; +import { Input, Space } from 'antd'; import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { css, useAPIClient, useCollectionManager_deprecated } from '../../..'; +import { CustomCascader, SchemaComponent } from '../..'; +import { css, useAPIClient } from '../../..'; import { mergeFilter } from '../../../filter-provider/utils'; -import { CustomCascader, SchemaComponent, useCompile, useDesignable } from '../..'; -import useServiceOptions, { useAssociationFieldContext } from './hooks'; +import { useAssociationFieldContext } from './hooks'; -const EMPTY = 'N/A'; const SchemaField = createSchemaField({ components: { Space, @@ -111,7 +118,9 @@ const Cascade = connect((props) => { setOptions(result); } }; - const filter = (inputValue: string, path) => path.some((option) => (option.label as string).includes(inputValue)); + + const filter = (inputValue: string, path) => + path.some((option) => fuzzysearch(inputValue, (option.label as string) ?? '')); return ( { export const nextTick = (fn: () => void) => { setTimeout(fn); }; + +export function fuzzysearch(needle: string, haystack: string): boolean { + const hlen = haystack.length; + const nlen = needle.length; + if (nlen > hlen) { + return false; + } + if (nlen === hlen) { + return needle === haystack; + } + outer: for (let i = 0, j = 0; i < nlen; i++) { + const nch = needle.charCodeAt(i); + while (j < hlen) { + if (haystack.charCodeAt(j++) === nch) { + continue outer; + } + } + return false; + } + return true; +}