8000 refactor(CollapseGroup): get rid of additional generics in component … · consta-design-system/uikit@bbe62f4 · GitHub
[go: up one dir, main page]

Skip to content

Commit bbe62f4

Browse files
committed
refactor(CollapseGroup): get rid of additional generics in component types
1 parent edbb728 commit bbe62f4

File tree

8 files changed

+94
-113
lines changed

8 files changed

+94
-113
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
"ts-essentials": "^3.0.0",
164164
"ts-jest": "^25.4.0",
165165
"ts-node": "^8.8.2",
166-
"typescript": "3.9.9",
166+
"typescript": "4.3.5",
167167
"typescript-eslint-parser": "^22.0.0"
168168
},
169169
"homepage": "https://consta-uikit.vercel.app"

src/components/CollapseGroup/__stories__/CollapseGroup.stories.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ export function Playground() {
7575
<CollapseGroup
7676
style={{ maxWidth: 300 }}
7777
items={items}
78-
isAccordion={isAccordion}
78+
{...(isAccordion
79+
? {
80+
isAccordion: true,
81+
}
82+
: {
83+
isAccordion: false,
84+
})}
7985
size={size}
8086
hoverEffect={hoverEffect}
8187
view={view}

src/components/CollapseGroup/__tests__/CollapseGroup.test.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ const getItemLabel = (item: Item) => item.name;
3737
const getItemContent = (item: Item) => item.text;
3838
const getItemRightSide = () => defaultRightSide;
3939

40-
function renderComponent<ITEM, IS_ACCORDION extends boolean = false>(
41-
props: CollapseGroupProps<ITEM, IS_ACCORDION>,
42-
) {
40+
function renderComponent<ITEM>(props: CollapseGroupProps<ITEM>) {
4341
return render(<CollapseGroup data-testid={testId} {...props} />);
4442
}
4543

src/components/CollapseGroup/helpers.ts

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,66 +15,63 @@ export type DefaultItem = {
1515
rightSide?: React.ReactNode | React.ReactNode[];
1616
};
1717

18-
export type CollapseGroupPropOnOpen<IS_ACCORDION> = (params: {
19-
e: React.MouseEvent<HTMLDivElement, MouseEvent>;
20-
value: (IS_ACCORDION extends true ? number : number[]) | null;
21-
}) => void;
22-
23-
export type CollapseGroupPropOpened<IS_ACCORDION> =
24-
| (IS_ACCORDION extends true ? number : number[])
25-
| null
26-
| undefined;
27-
2818
type CollapseGroupPropGetItemLabel<ITEM> = (item: ITEM) => string;
2919
type CollapseGroupPropGetItemContent<ITEM> = (item: ITEM) => React.ReactNode;
3020
type CollapseGroupPropGetItemRightSide<ITEM> = (
3121
item: ITEM,
3222
) => React.ReactNode | React.ReactNode[] | undefined;
3323

34-
export type CollapseGroupProps<ITEM, IS_ACCORDION extends boolean> = PropsWithHTMLAttributesAndRef<
24+
export type CollapseGroupProps<ITEM> = PropsWithHTMLAttributesAndRef<
3525
{
3626
items: ITEM[];
37-
isAccordion?: IS_ACCORDION;
3827
children?: never;
3928
icon?: React.FC<IconProps>;
4029
divider?: boolean;
4130
size?: CollapsePropSize;
4231
view?: CollapsePropView;
4332
horizontalSpace?: CollapsePropHorizontalSpace;
4433
hoverEffect?: boolean;
45-
onOpen?: CollapseGroupPropOnOpen<IS_ACCORDION>;
46-
opened?: CollapseGroupPropOpened<IS_ACCORDION>;
47-
getItemLabel?: CollapseGroupPropGetItemLabel<ITEM>;
48-
getItemContent?: CollapseGroupPropGetItemContent<ITEM>;
4934
} & (
5035
| {
51-
closeIcon: React.FC<IconProps>;
52-
directionIcon?: never;
53-
closeDirectionIcon?: never;
36+
isAccordion: true;
37+
opened?: number | null;
38+
onOpen?: (params: { value: number | null }) => void;
5439
}
5540
| {
56-
closeIcon?: never;
57-
directionIcon?: CollapseIconPropDirection;
58-
closeDirectionIcon?: CollapseIconPropDirection;
41+
isAccordion?: false;
42+
opened?: number[] | null;
43+
onOpen?: (params: { value: number[] | null }) => void;
5944
}
6045
) &
46+
(
47+
| {
48+
closeIcon: React.FC<IconProps>;
49+
directionIcon?: never;
50+
closeDirectionIcon?: never;
51+
}
52+
| {
53+
closeIcon?: never;
54+
directionIcon?: CollapseIconPropDirection;
55+
closeDirectionIcon?: CollapseIconPropDirection;
56+
}
57+
) &
6158
(
6259
| {
6360
iconPosition?: 'left';
6461
getItemRightSide?: CollapseGroupPropGetItemRightSide<ITEM>;
6562
}
6663
| {
67-
iconPosition?: 'right';
64+
iconPosition: 'right';
6865
getItemRightSide?: never;
6966
}
7067
),
7168
HTMLDivElement
7269
> &
7370
(ITEM extends { label: DefaultItem['label'] }
74-
? {}
71+
? { getItemLabel?: never }
7572
: { getItemLabel: CollapseGroupPropGetItemLabel<ITEM> }) &
7673
(ITEM extends { content: DefaultItem['content'] }
77-
? {}
74+
? { getItemContent?: never }
7875
: { getItemContent: CollapseGroupPropGetItemContent<ITEM> });
7976

8077
export const defaultGetItemLabel: CollapseGroupPropGetItemLabel<DefaultItem> = (item) => item.label;
@@ -83,18 +80,16 @@ export const defaultGetItemContent: CollapseGroupPropGetItemContent<DefaultItem>
8380
export const defaultGetItemRightSide: CollapseGroupPropGetItemContent<DefaultItem> = (item) =>
8481
item.rightSide;
8582

86-
export type CollapseGroupComponent = <ITEM, IS_ACCORDION extends boolean = false>(
87-
props: CollapseGroupProps<ITEM, IS_ACCORDION>,
83+
export type CollapseGroupComponent = <ITEM>(
84+
props: CollapseGroupProps<ITEM>,
8885
) => React.ReactElement | null;
8986

90-
export type CollapseGroupRenderFunction = <ITEM, IS_ACCORDION extends boolean = false>(
91-
props: CollapseGroupProps<ITEM, IS_ACCORDION>,
87+
export type CollapseGroupRenderFunction = <ITEM>(
88+
props: CollapseGroupProps<ITEM>,
9289
ref: React.Ref<HTMLDivElement>,
9390
) => React.ReactElement | null;
9491

95-
export function withDefaultGetters<ITEM, IS_ACCORDION extends boolean>(
96-
props: CollapseGroupProps<ITEM, IS_ACCORDION>,
97-
) {
92+
export function withDefaultGetters<ITEM>(props: CollapseGroupProps<ITEM>) {
9893
return {
9994
...props,
10095
getItemLabel: props.getItemLabel || defaultGetItemLabel,

src/components/CollapseGroup/useChoice.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,33 @@ import { useEffect, useState } from 'react';
22

33
import { useChoiceGroupIndexed } from '../../hooks/useChoiceGroupIndexed/useChoiceGroupIndexed';
44

5-
import { CollapseGroupPropOnOpen, CollapseGroupPropOpened, CollapseGroupProps } from './helpers';
5+
import { CollapseGroupProps } from './helpers';
66

7-
type ChoiceGroupIndexedParams = {
8-
value: CollapseGroupPropOpened<boolean>;
9-
multiple: boolean;
10-
callBack: CollapseGroupPropOnOpen<boolean>;
11-
};
12-
13-
export const useChoice = <ITEM, IS_ACCORDION extends boolean>(
14-
props: CollapseGroupProps<ITEM, IS_ACCORDION>,
15-
) => {
16-
const [openedKeys, setOpenedKeys] = useState<typeof props.opened>(props.opened);
17-
18-
const callBack: CollapseGroupPropOnOpen<E 10000 xclude<typeof props.isAccordion, undefined>> = (
19-
params,
20-
) => {
21-
setOpenedKeys(params.value);
22-
props.onOpen?.(params);
23-
};
24-
25-
const choiceGroupIndexedParams: ChoiceGroupIndexedParams = {
26-
value: openedKeys,
27-
multiple: !props.isAccordion,
28-
callBack,
29-
};
7+
export const useChoice = <ITEM>(props: CollapseGroupProps<ITEM>) => {
8+
const [openedKeys, setOpenedKeys] = useState(props.opened);
309

3110
useEffect(() => {
3211
setOpenedKeys(props.opened);
3312
}, [props.opened]);
3413

35-
return useChoiceGroupIndexed(choiceGroupIndexedParams);
14+
return useChoiceGroupIndexed(
15+
props.isAccordion
16+
? {
17+
value: (openedKeys as typeof props.opened) ?? null,
18+
multiple: false,
19+
callBack: (params) => {
20+
setOpenedKeys(params.value);
21+
props.onOpen?.(params);
22+
},
23+
isNullableValue: true,
24+
}
25+
: {
26+
value: (openedKeys as typeof props.opened) ?? [],
27+
multiple: true,
28+
callBack: (params) => {
29+
setOpenedKeys(params.value);
30+
props.onOpen?.(params);
31+
},
32+
},
33+
);
3634
};

src/components/Table/__stories__/Table.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ export const withCustomFilters = createStory(
343343
() => {
344344
return (
345345
<div className={cnTableStories()}>
346-
<Table {...getKnobs({ filters: customFilters })} />
346+
<Table {...getKnobs<typeof tableData.rows[number]>({ filters: customFilters })} />
347347
</div>
348348
);
349349
},

src/hooks/useChoiceGroupIndexed/useChoiceGroupIndexed.ts

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
import React from 'react';
22

3-
type ValueMultiple = number[] | null;
4-
type ValueNotMultiple<IS_NULLABLE_VALUE> = IS_NULLABLE_VALUE extends true ? number | null : number;
5-
6-
type UseChoiceGroupIndexedParams<
7-
MULTIPLE extends boolean = false,
8-
IS_NULLABLE_VALUE extends boolean = false,
9-
EVENT = React.MouseEvent<HTMLDivElement, MouseEvent>
10-
> = {
11-
value: (MULTIPLE extends true ? ValueMultiple : ValueNotMultiple<IS_NULLABLE_VALUE>) | undefined;
12-
multiple: MULTIPLE;
13-
callBack: (props: {
14-
e: EVENT;
15-
value: MULTIPLE extends true ? ValueMultiple : ValueNotMultiple<IS_NULLABLE_VALUE>;
16-
}) => void;
17-
isNullableValue?: IS_NULLABLE_VALUE;
18-
};
19-
20-
function isMultiple<EVENT>(
21-
params: UseChoiceGroupIndexedParams<boolean, boolean, EVENT>,
22-
): params is UseChoiceGroupIndexedParams<true, boolean, EVENT> {
23-
return !!params.multiple;
24-
}
25-
26-
function isNotMultiple<EVENT>(
27-
params: UseChoiceGroupIndexedParams<boolean, boolean, EVENT>,
28-
): params is UseChoiceGroupIndexedParams<false, boolean, EVENT> {
29-
return !params.multiple;
30-
}
3+
type ChangeEvent = React.MouseEvent<HTMLDivElement, MouseEvent>;
4+
type CallBack<VALUE> = (props: { e: ChangeEvent; value: VALUE }) => void;
5+
6+
type UseChoiceGroupIndexedParams =
7+
| {
8+
multiple: true;
9+
isNullableValue?: never;
10+
value: number[] | null;
11+
callBack: CallBack<number[] | null>;
12+
}
13+
| {
14+
multiple: false;
15+
isNullableValue: true;
16+
value: number | null;
17+
callBack: CallBack<number | null>;
18+
}
19+
| {
20+
multiple: false;
21+
isNullableValue: false;
22+
value: number;
23+
callBack: CallBack<number>;
24+
};
3125

3226
function formatValue(value: number[] | number | null | undefined) {
3327
if (Array.isArray(value)) {
@@ -39,17 +33,13 @@ function formatValue(value: number[] | number | null | undefined) {
3933
return [];
4034
}
4135

42-
export function useChoiceGroupIndexed<
43-
MULTIPLE extends boolean,
44-
IS_NULLABLE_VALUE extends boolean,
45-
EVENT
46-
>(props: UseChoiceGroupIndexedParams<MULTIPLE, IS_NULLABLE_VALUE, EVENT>) {
36+
export function useChoiceGroupIndexed(props: UseChoiceGroupIndexedParams) {
4737
const value = formatValue(props.value);
4838

4939
const getChecked = (index: number) => value.includes(index);
5040

51-
const getOnChange = (index: number) => (e: EVENT) => {
52-
if (isMultiple(props)) {
41+
const getOnChange = (index: number) => (e: ChangeEvent) => {
42+
if (props.multiple) {
5343
let newValue: number[] | null;
5444
if (getChecked(index)) {
5545
newValue = value.filter((item) => item !== index);
@@ -58,19 +48,13 @@ export function useChoiceGroupIndexed<
5848
newValue = null;
5949
}
6050
} else {
61-
newValue = [...value];
62-
newValue.push(index);
51+
newValue = [...value, index];
6352
}
6453
props.callBack({ e, value: newValue });
65-
return;
66-
}
67-
68-
if (isNotMultiple(props)) {
69-
if (props.isNullableValue && getChecked(index)) {
70-
props.callBack({ e, value: null });
71-
} else {
72-
props.callBack({ e, value: index });
73-
}
54+
} else if (props.isNullableValue && getChecked(index)) {
55+
props.callBack({ e, value: null });
56+
} else {
57+
props.callBack({ e, value: index });
7458
}
7559
};
7660

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17828,10 +17828,10 @@ typescript-estree@18.0.0:
1782817828
lodash.unescape "4.0.1"
1782917829
semver "5.5.0"
1783017830

17831-
typescript@3.9.9:
17832-
version "3.9.9"
17833-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
17834-
integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uov 5E62 NN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
17831+
typescript@4.3.5:
17832+
version "4.3.5"
17833+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
17834+
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
1783517835

1783617836
uglify-js@3.4.x:
1783717837
version "3.4.10"

0 commit comments

Comments
 (0)
0