Skip to content

Commit

Permalink
feat(core): add selectedOptionsOrder in useSelect (#6071)
Browse files Browse the repository at this point in the history
Co-authored-by: Batuhan Wilhelm <batuhanwilhelm@gmail.com>
Co-authored-by: Ali Emir Şen <senaliemir@gmail.com>
  • Loading branch information
3 people committed Jul 1, 2024
1 parent 4265ae2 commit 853bef9
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 6 deletions.
11 changes: 11 additions & 0 deletions .changeset/loud-zebras-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@refinedev/core": minor
"@refinedev/antd": minor
"@refinedev/mui": minor
---

feat: add `selectedOptionsOrder` in `useSelect`

Now with `selectedOptionsOrder`, you can sort `selectedOptions` at the top of list when use `useSelect` with `defaultValue`.

Resolves [#6061](https://github.com/refinedev/refine/issues/6061)
14 changes: 14 additions & 0 deletions documentation/docs/data/hooks/use-select/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,20 @@ useSelect({
});
```

### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
useSelect({
defaultValue: 1, // or [1, 2]
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

> For more information, refer to the [`useMany` documentation&#8594](/docs/data/hooks/use-many)
### debounce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,23 @@ const { selectProps } = useCheckboxGroup({
});
```

### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
const { selectProps } = useCheckboxGroup({
resource: "languages",
// highlight-next-line
defaultValue: [1, 2],
// highlight-next-line
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

The easiest way to select default values for checkbox fields is by passing in `defaultValue`.

### optionLabel and optionValue
Expand Down Expand Up @@ -260,3 +277,7 @@ Use `sorters` instead.

[baserecord]: /docs/core/interface-references#baserecord
[httperror]: /docs/core/interface-references#httperror

```
```
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ const { selectProps } = useRadioGroup({
});
```

### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
const { selectProps } = useRadioGroup({
resource: "languages",
// highlight-next-line
defaultValue: 1,
// highlight-next-line
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

The easiest way to selecting a default value for an radio button field is by passing in `defaultValue`.

### optionLabel and optionValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ useSelect({
});
```

### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
useSelect({
defaultValue: 1, // or [1, 2]
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

> For more information, refer to the [`useMany` documentation &#8594](/docs/data/hooks/use-many)
### debounce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,20 @@ useSelect({

> For more information, refer to the [`useMany` documentation &#8594](/docs/data/hooks/use-many)
### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
useSelect({
defaultValue: 1, // or [1, 2]
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

### debounce

`debounce` allows us to `debounce` the `onSearch` function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ useAutocomplete({
});
```

### selectedOptionsOrder

`selectedOptionsOrder` allows us to sort `selectedOptions` on `defaultValue`. It can be:

- `"in-place"`: sort `selectedOptions` at the bottom. It is by default.
- `"selected-first"`: sort `selectedOptions` at the top.

```tsx
useAutocomplete({
defaultValue: 1, // or [1, 2]
selectedOptionsOrder: "selected-first", // in-place | selected-first
});
```

> For more information, refer to the [`useMany` documentation &#8594](/docs/data/hooks/use-many)
### debounce
Expand Down
2 changes: 2 additions & 0 deletions packages/antd/src/hooks/fields/useCheckboxGroup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const useCheckboxGroup = <
pagination,
liveMode,
defaultValue,
selectedOptionsOrder,
onLiveEvent,
liveParams,
meta,
Expand Down Expand Up @@ -90,6 +91,7 @@ export const useCheckboxGroup = <
pagination,
liveMode,
defaultValue,
selectedOptionsOrder,
onLiveEvent,
liveParams,
meta: pickNotDeprecated(meta, metaData),
Expand Down
2 changes: 2 additions & 0 deletions packages/antd/src/hooks/fields/useRadioGroup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const useRadioGroup = <
pagination,
liveMode,
defaultValue,
selectedOptionsOrder,
onLiveEvent,
liveParams,
meta,
Expand All @@ -86,6 +87,7 @@ export const useRadioGroup = <
pagination,
liveMode,
defaultValue,
selectedOptionsOrder,
onLiveEvent,
liveParams,
meta: pickNotDeprecated(meta, metaData),
Expand Down
42 changes: 42 additions & 0 deletions packages/core/src/hooks/useSelect/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { waitFor } from "@testing-library/react";
import { renderHook } from "@testing-library/react-hooks";

import { MockJSONServer, TestWrapper, act, mockRouterProvider } from "@test";
import { posts } from "@test/dataMocks";

import type {
CrudFilter,
Expand Down Expand Up @@ -440,6 +441,47 @@ describe("useSelect Hook", () => {
expect(mockFunc).toBeCalledTimes(2);
});

it("should sort default data first with selectedOptionsOrder for defaultValue", async () => {
const { result } = renderHook(
() =>
useSelect({
resource: "posts",
defaultValue: ["2"],
selectedOptionsOrder: "selected-first",
}),
{
wrapper: TestWrapper({
dataProvider: {
default: {
...MockJSONServer.default,
// Default `getMany` mock returns all posts, we need to update it to return appropriate posts
getMany: ({ ids }) => {
return Promise.resolve({
data: posts.filter((post) => ids.includes(post.id)) as any,
});
},
},
},
resources: [{ name: "posts" }],
}),
},
);

await waitFor(() => {
expect(result.current.queryResult.isSuccess).toBeTruthy();
});

expect(result.current.options).toHaveLength(2);
expect(result.current.options).toEqual([
{ label: "Recusandae consectetur aut atque est.", value: "2" },
{
label:
"Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
value: "1",
},
]);
});

it("should invoke queryOptions methods for default value successfully", async () => {
const mockFunc = jest.fn();

Expand Down
16 changes: 15 additions & 1 deletion packages/core/src/hooks/useSelect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
useLoadingOvertime,
} from "../useLoadingOvertime";

export type SelectedOptionsOrder = "in-place" | "selected-first";

export type UseSelectProps<TQueryFnData, TError, TData> = {
/**
* Resource name for API data interactions
Expand Down Expand Up @@ -84,6 +86,11 @@ export type UseSelectProps<TQueryFnData, TError, TData> = {
* Adds extra `options`
*/
defaultValue?: BaseKey | BaseKey[];
/**
* Allow us to sort the selection options
* @default `in-place`
*/
selectedOptionsOrder?: SelectedOptionsOrder;
/**
* The number of milliseconds to delay
* @default `300`
Expand Down Expand Up @@ -213,6 +220,7 @@ export const useSelect = <
hasPagination = false,
liveMode,
defaultValue = [],
selectedOptionsOrder = "in-place",
onLiveEvent,
onSearch: onSearchFromProp,
liveParams,
Expand Down Expand Up @@ -362,7 +370,13 @@ export const useSelect = <
});

const combinedOptions = useMemo(
() => uniqBy([...options, ...selectedOptions], "value"),
() =>
uniqBy(
selectedOptionsOrder === "in-place"
? [...options, ...selectedOptions]
: [...selectedOptions, ...options],
"value",
),
[options, selectedOptions],
);

Expand Down
17 changes: 12 additions & 5 deletions packages/mui/src/hooks/useAutocomplete/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,18 @@ export const useAutocomplete = <

return {
autocompleteProps: {
options: unionWith(
queryResult.data?.data || [],
defaultValueQueryResult.data?.data || [],
isEqual,
),
options:
props.selectedOptionsOrder === "selected-first"
? unionWith(
defaultValueQueryResult.data?.data || [],
queryResult.data?.data || [],
isEqual,
)
: unionWith(
queryResult.data?.data || [],
defaultValueQueryResult.data?.data || [],
isEqual,
),
loading: queryResult.isFetching || defaultValueQueryResult.isFetching,
onInputChange: (event, value) => {
if (event?.type === "change") {
Expand Down

0 comments on commit 853bef9

Please sign in to comment.