Skip to content

Commit

Permalink
refactor: update useFilterSelect to allow retain filter and arguments…
Browse files Browse the repository at this point in the history
… when field is changed
  • Loading branch information
lawvs committed Aug 9, 2024
1 parent c5ad41a commit 311f306
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 10 deletions.
32 changes: 32 additions & 0 deletions .changeset/wild-hairs-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@fn-sphere/filter": patch
---

- Added the ability to retain the current filter and arguments when the field is changed in the `useFilterSelect` hook.
- Introduced the `UpdateFieldOptions` type to specify the behavior when updating the field.
- Updated the `FieldSelect` component to pass the `updateFieldOptions` to the `updateField` function.

```tsx
export type UpdateFieldOptions = {
/**
* Try to continue using the current filter when the field is changed.
*
* @default true
*/
tryRetainFilter?: boolean;
/**
* Automatically select the first filter when the field is changed and the filter is not retained.
*
* @default true
*/
autoSelectFirstFilter?: boolean;
/**
* Try to continue using the current args when the field is changed.
*
* @default true
*/
tryRetainArgs?: boolean;
};

<FieldSelect rule={rule} tryRetainFilter autoSelectFirstFilter tryRetainArgs />;
```
57 changes: 51 additions & 6 deletions packages/filter/src/hooks/use-filter-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ import {
import { useFilterRule } from "./use-filter-rule.js";
import { useFilterSchemaContext } from "./use-filter-schema-context.js";

export type UpdateFieldOptions = {
/**
* Try to continue using the current filter when the field is changed.
*
* @default true
*/
tryRetainFilter?: boolean;
/**
* Automatically select the first filter when the field is changed and the filter is not retained.
*
* @default true
*/
autoSelectFirstFilter?: boolean;
/**
* Try to continue using the current args when the field is changed.
*
* @default true
*/
tryRetainArgs?: boolean;
};

export const useFilterSelect = (rule: SingleFilter) => {
const {
filterMap,
Expand Down Expand Up @@ -46,15 +67,39 @@ export const useFilterSelect = (rule: SingleFilter) => {
value: filter,
}));

const updateField = (newField: FilterField) => {
const updateField = (
newField: FilterField,
{
tryRetainFilter = true,
autoSelectFirstFilter = true,
tryRetainArgs = true,
}: UpdateFieldOptions = {},
) => {
if (!newField.filterFnList.length) {
console.error("Field has no filter", newField);
throw new Error("Field has no filter");
}
// Retain filter when possible
const canRetainFilter = newField.filterFnList.some(
(filter) => filter.name === rule.name,
);
const needRetainFilter = tryRetainFilter && canRetainFilter;
const fallbackFilter = autoSelectFirstFilter
? newField.filterFnList[0].name
: undefined;

// TODO check if the arguments are matched new filter when autoSelectFirstFilter enabled
const needRetainArgs = tryRetainArgs && needRetainFilter;

updateRule({
...rule,
path: newField.path,
// Clear filter name when field changed
name: undefined,
// name: newField.filterFnList[0].name,
// Reset arguments when field changed
args: [],
name: needRetainFilter ? rule.name : fallbackFilter,
// If the filter is retained, keep the arguments
args: needRetainArgs
? rule.args
: // Reset arguments when field changed
[],
});
};

Expand Down
14 changes: 10 additions & 4 deletions packages/filter/src/views/field-select.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import type { SingleFilter } from "@fn-sphere/core";
import { useFilterSelect } from "../hooks/use-filter-select.js";
import {
useFilterSelect,
type UpdateFieldOptions,
} from "../hooks/use-filter-select.js";
import { useView } from "../theme/index.js";

export type FieldSelectProps = {
rule: SingleFilter;
};
} & UpdateFieldOptions;

export const FieldSelect = ({ rule }: FieldSelectProps) => {
export const FieldSelect = ({
rule,
...updateFieldOptions
}: FieldSelectProps) => {
const { Select: SelectView } = useView("components");
const { selectedField, fieldOptions, updateField } = useFilterSelect(rule);

return (
<SelectView
value={selectedField}
options={fieldOptions}
onChange={updateField}
onChange={(field) => updateField(field, updateFieldOptions)}
/>
);
};
Expand Down

0 comments on commit 311f306

Please sign in to comment.