Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(TreeSelect): added generic value depending on the multiple prop #1894

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export interface TableColumnSetupProps {
sortable?: boolean;

onUpdate: (newSettings: TableSetting[]) => void;
popupWidth?: TreeSelectProps<unknown>['popupWidth'];
popupWidth?: TreeSelectProps['popupWidth'];
popupPlacement?: PopperPlacement;

/**
Expand Down Expand Up @@ -379,7 +379,7 @@ export const TableColumnSetup = (props: TableColumnSetupProps) => {

const dndRenderItem = useDndRenderItem(sortingEnabled);

const renderControl: TreeSelectProps<unknown>['renderControl'] = ({toggleOpen}) => {
const renderControl: TreeSelectProps['renderControl'] = ({toggleOpen}) => {
const onKeyDown = createOnKeyDownHandler(toggleOpen);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export function getActualItems<I>(
}

export interface WithTableSettingsOptions {
width?: TreeSelectProps<any>['popupWidth'];
width?: TreeSelectProps['popupWidth'];
sortable?: boolean;
filterable?: boolean;
}
Expand All @@ -119,7 +119,7 @@ interface WithTableSettingsBaseProps {
/**
* @deprecated Use factory notation: "withTableSettings({width: <value>})(Table)"
*/
settingsPopupWidth?: TreeSelectProps<any>['popupWidth'];
settingsPopupWidth?: TreeSelectProps['popupWidth'];

settings: TableSettingsData;
updateSettings: (data: TableSettingsData) => void;
Expand Down
45 changes: 38 additions & 7 deletions src/components/TreeSelect/TreeSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {block} from '../utils/cn';
import type {CnMods} from '../utils/cn';

import {useControlledValue} from './hooks/useControlledValue';
import type {TreeSelectProps, TreeSelectRenderControlProps} from './types';
import type {TreeSelectGetValue, TreeSelectProps, TreeSelectRenderControlProps} from './types';

import './TreeSelect.scss';

Expand All @@ -27,7 +27,11 @@ const defaultItemRenderer: TreeListRenderItem<unknown> = (renderState) => {
return <ListItemView {...renderState.props} {...renderState.renderContainerProps} />;
};

export const TreeSelect = React.forwardRef(function TreeSelect<T, P extends {} = {}>(
export const TreeSelect = React.forwardRef(function TreeSelect<
T,
P extends {} = {},
M extends boolean = false,
>(
{
id,
qa,
Expand Down Expand Up @@ -68,7 +72,7 @@ export const TreeSelect = React.forwardRef(function TreeSelect<T, P extends {} =
onBlur,
getItemId,
onItemClick,
}: TreeSelectProps<T, P>,
}: TreeSelectProps<T, P, M>,
ref: React.Ref<HTMLButtonElement>,
) {
const mobile = useMobile();
Expand Down Expand Up @@ -103,10 +107,37 @@ export const TreeSelect = React.forwardRef(function TreeSelect<T, P extends {} =
open: propsOpen,
});

const handleUpdate = React.useCallback(
(nextValue: string[]) => {
if (onUpdate) {
if (multiple) {
onUpdate(nextValue as TreeSelectGetValue<M>);
} else {
const [vl] = nextValue;

onUpdate(vl as TreeSelectGetValue<M>);
}
}
},
[multiple, onUpdate],
);

const computedValue = React.useMemo(() => {
let result: string[] = [];

if (Array.isArray(propsValue)) {
result = propsValue;
} else if (typeof propsValue !== 'undefined') {
result = [propsValue];
}

return result;
}, [propsValue]);

const {value, selectedById, setSelected} = useControlledValue({
value: propsValue,
value: computedValue,
defaultValue,
onUpdate,
onUpdate: handleUpdate,
});

const list = useList({
Expand Down Expand Up @@ -264,6 +295,6 @@ export const TreeSelect = React.forwardRef(function TreeSelect<T, P extends {} =
/>
</div>
);
}) as <T, P extends {} = {}>(
props: TreeSelectProps<T, P> & {ref?: React.Ref<HTMLDivElement>},
}) as <T, P extends {} = {}, M extends boolean = false>(
props: TreeSelectProps<T, P, M> & {ref?: React.Ref<HTMLDivElement>},
) => React.ReactElement;
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const InfinityScrollExample = ({
itemsCount = 5,
...storyProps
}: InfinityScrollExampleProps) => {
const [value, setValue] = React.useState<string[]>([]);
const [value, setValue] = React.useState<string | undefined>();
const {
data: items = [],
onFetchMore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type CustomDataType = {someRandomKey: string; id: string};
export interface WithDndListExampleProps
extends Omit<
TreeSelectProps<CustomDataType>,
'value' | 'onUpdate' | 'items' | 'mapItemDataToContentProps'
'value' | 'onUpdate' | 'items' | 'mapItemDataToContentProps' | 'multiple'
> {}

const randomItems: CustomDataType[] = createRandomizedData({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ export interface WithItemLinksAndActionsExampleProps
> {}

export const WithItemLinksAndActionsExample = (storyProps: WithItemLinksAndActionsExampleProps) => {
const [value, setValue] = React.useState<string[]>([]);
const [value, setValue] = React.useState<string | undefined>();
const [open, setOpen] = React.useState(true);
const items = React.useMemo(() => createRandomizedData({num: 10, depth: 1}), []);

const onItemClick = (id: ListItemId, list: UseListResult<{title: string}>) => {
if (list.state.disabledById[id]) return;

setValue([id]);
setValue(id);

list.state.setActiveItemId(id);

Expand Down
2 changes: 1 addition & 1 deletion src/components/TreeSelect/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {TreeSelect} from './TreeSelect';
export type {TreeSelectProps, TreeSelectRenderItem} from './types';
export type {TreeSelectProps, TreeSelectRenderItem, TreeSelectGetValue} from './types';
16 changes: 10 additions & 6 deletions src/components/TreeSelect/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@ export type TreeSelectRenderItem<T, P extends {} = {}> = TreeListRenderItem<T, P
export type TreeSelectRenderContainerProps<T> = TreeListContainerProps<T>;
export type TreeSelectRenderContainer<T> = TreeListRenderContainer<T>;

interface TreeSelectBehavioralProps<T> extends UseListParsedStateProps<T> {
interface TreeSelectBehavioralProps<T, M extends boolean> extends UseListParsedStateProps<T> {
withExpandedState?: boolean;
multiple?: boolean;
multiple?: M;
}

export interface TreeSelectProps<T, P extends {} = {}>
export type TreeSelectGetValue<M extends boolean> = M extends true
? ListItemId[]
: ListItemId | undefined;

export interface TreeSelectProps<T = {}, P extends {} = {}, M extends boolean = false>
extends Omit<TreeListProps<T, P>, 'list' | 'renderContainer' | 'multiple'>,
Pick<
TreeSelectRenderControlProps<T>,
Expand All @@ -63,8 +67,8 @@ export interface TreeSelectProps<T, P extends {} = {}>
| 'errorMessage'
>,
UseOpenProps,
TreeSelectBehavioralProps<T> {
value?: ListItemId[];
TreeSelectBehavioralProps<T, M> {
value?: TreeSelectGetValue<M>;
defaultValue?: ListItemId[] | undefined;
popupClassName?: string;
popupWidth?: SelectPopupProps['width'];
Expand All @@ -82,7 +86,7 @@ export interface TreeSelectProps<T, P extends {} = {}>
* In other situations use `renderContainer` method
*/
slotAfterListBody?: React.ReactNode;
onUpdate?(value: ListItemId[]): void;
onUpdate?(value: TreeSelectGetValue<M>): void;
/**
* Ability to override custom toggler button
*/
Expand Down
8 changes: 4 additions & 4 deletions src/components/useList/utils/getListItemClickHandler.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type {ListOnItemClick, UseListResult} from '../types';

interface GetListItemClickHandlerProps<T> {
multiple?: boolean;
interface GetListItemClickHandlerProps<T, M> {
multiple?: M;
list: UseListResult<T>;
}

export const getListItemClickHandler = <T = unknown>({
export const getListItemClickHandler = <T = unknown, M extends boolean = false>({
list,
multiple,
}: GetListItemClickHandlerProps<T>) => {
}: GetListItemClickHandlerProps<T, M>) => {
const onItemClick: ListOnItemClick = ({id}) => {
if (list.state.disabledById[id]) return;

Expand Down
2 changes: 2 additions & 0 deletions src/unstable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export {
export {
TreeSelect as unstable_TreeSelect,
type TreeSelectProps as unstable_TreeSelectProps,
type TreeSelectRenderItem as unstable_TreeSelectRenderItem,
type TreeSelectGetValue as unstable_TreeSelectGetValue,
} from './components/TreeSelect';
export {
TreeList as unstable_TreeList,
Expand Down
Loading