Skip to content

Commit

Permalink
Merge pull request #692 from oceanbase/dengfuping-dev
Browse files Browse the repository at this point in the history
demo(design): Add remote search demo for Select
  • Loading branch information
dengfuping authored Sep 2, 2024
2 parents b4238c0 + 43d65b6 commit a963b6d
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 2 deletions.
90 changes: 90 additions & 0 deletions packages/design/src/select/demo/remote-search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useMemo, useRef, useState } from 'react';
import { Select, Spin } from '@oceanbase/design';
import type { SelectProps } from '@oceanbase/design';
import debounce from 'lodash/debounce';

export interface DebounceSelectProps<ValueType = any>
extends Omit<SelectProps<ValueType | ValueType[]>, 'options' | 'children'> {
fetchOptions: (search: string) => Promise<ValueType[]>;
debounceTimeout?: number;
}

function DebounceSelect<
ValueType extends { key?: string; label: React.ReactNode; value: string | number } = any,
>({ fetchOptions, debounceTimeout = 800, ...props }: DebounceSelectProps<ValueType>) {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState<ValueType[]>([]);
const fetchRef = useRef(0);

const debounceFetcher = useMemo(() => {
const loadOptions = (value: string) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);

fetchOptions(value).then(newOptions => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}

setOptions(newOptions);
setFetching(false);
});
};

return debounce(loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);

return (
<Select
labelInValue
filterOption={false}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
);
}

// Usage of DebounceSelect
interface UserValue {
label: string;
value: string;
}

async function fetchUserList(username: string): Promise<UserValue[]> {
console.log('fetching user', username);

return fetch('https://randomuser.me/api/?results=5')
.then(response => response.json())
.then(body =>
body.results.map(
(user: { name: { first: string; last: string }; login: { username: string } }) => ({
label: `${user.name.first} ${user.name.last}`,
value: user.login.username,
})
)
);
}

const App: React.FC = () => {
const [value, setValue] = useState<UserValue[]>([]);

return (
<DebounceSelect
mode="multiple"
value={value}
placeholder="Select users"
fetchOptions={fetchUserList}
onChange={newValue => {
setValue(newValue as UserValue[]);
}}
style={{ width: '100%' }}
/>
);
};

export default App;
1 change: 1 addition & 0 deletions packages/design/src/select/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ demo:
<!-- prettier-ignore -->
<code src="./demo/basic.tsx" title="基本使用"></code>
<code src="./demo/multiple.tsx" title="多选"></code>
<code src="./demo/remote-search.tsx" title="远程搜索" description="带防抖控制、请求时序控制和加载状态展示"></code>
<code src="./demo/tags.tsx" title="标签" description="标签式选择,支持输入任意内容"></code>
<code src="./demo/variant.tsx" title="多种展示形式" description="支持 `outlined`、`filled` 和 `borderless` 三种形态。"></code>
<code src="./demo/custom-tag-render.tsx" title="自定义标签样式" description="允许自定义选择标签的样式"></code>
Expand Down
2 changes: 1 addition & 1 deletion packages/design/src/select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type SelectLocale = AntLocale['Select'] & {
placeholder?: string;
};

export interface SelectProps extends AntSelectProps {
export interface SelectProps<T> extends AntSelectProps<T> {
locale?: SelectLocale;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/design/src/spin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ demo:

<!-- prettier-ignore -->
<code src="./demo/basic.tsx" title="基本用法" description="一个简单的 loading 状态"></code>
<code src="./demo/size.tsx" title="各种大小" description="小的用于文本加载,默认用于卡片容器级加载,大的用于**页面级**加载"></code>
<code src="./demo/size.tsx" title="各种大小" description="小的用于文本加载,默认用于卡片容器级加载,大的用于页面级加载"></code>
<code src="./demo/colored.tsx" title="彩色的加载指示符"></code>
<code src="./demo/inside.tsx" title="放入一个容器中"></code>
<code src="./demo/nested.tsx" title="卡片加载中" description="可以直接把内容内嵌到 `Spin` 中,将现有容器变为加载状态"></code>
Expand Down

0 comments on commit a963b6d

Please sign in to comment.