Skip to content

Commit c0c211f

Browse files
committed
feat: Update Dropdown component to use structured icon props
- Refactor Dropdown component to accept icon properties as an object with iconName, className, and dataTestId - Update related components and stories to reflect the new icon structure - Bump package version to 1.0.212
1 parent 4bae7c1 commit c0c211f

File tree

7 files changed

+112
-50
lines changed

7 files changed

+112
-50
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@programmer_network/yail",
3-
"version": "1.0.211",
3+
"version": "1.0.212",
44
"description": "Programmer Network's official UI library for React",
55
"author": "Aleksandar Grbic - (https://programmer.network)",
66
"publishConfig": {

src/Components/Dropdown/DefaultDropdown.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { FC } from "react";
22

3+
import Icon from "Components/Icon";
4+
35
import { IDefaultDropdownProps, IDropdownListItem } from "./types";
46

57
const DropdownListItem: FC<IDropdownListItem> = ({
@@ -17,7 +19,15 @@ const DropdownListItem: FC<IDropdownListItem> = ({
1719
}}
1820
>
1921
<div className='yl:flex yl:items-center'>
20-
{icon && <span className='yl:mr-2'>{icon}</span>}
22+
{icon && (
23+
<span className='yl:mr-2'>
24+
<Icon
25+
iconName={icon.iconName}
26+
className={icon.className}
27+
dataTestId={icon.dataTestId}
28+
/>
29+
</span>
30+
)}
2131
{value}
2232
</div>
2333
</li>
@@ -29,7 +39,15 @@ const DefaultDropdown: FC<IDefaultDropdownProps> = ({ options, setIsOpen }) => {
2939
<ul className='yl:p-2 yl:text-text'>
3040
{options.map((option, index) => (
3141
<DropdownListItem
32-
icon={option.icon}
42+
icon={
43+
option.icon
44+
? {
45+
iconName: option.icon?.iconName,
46+
className: option.icon?.className,
47+
dataTestId: option.icon?.dataTestId
48+
}
49+
: undefined
50+
}
3351
value={option.value}
3452
key={`${option.value}-${index}`}
3553
onClick={option.onClick}

src/Components/Dropdown/Dropdown.stories.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { Meta, StoryFn } from "@storybook/react";
22

3-
import Icon from "Components/Icon";
4-
53
import Dropdown from "./";
64
import { IDropdownProps } from "./types";
75

@@ -23,7 +21,10 @@ DefaultDropdown.args = {
2321
{
2422
value: "foo",
2523
onClick: () => console.log("clicked"),
26-
icon: <Icon iconName='IconShare' className='yl:w-4' />
24+
icon: {
25+
iconName: "IconShare",
26+
className: "yl:w-4"
27+
}
2728
}
2829
]
2930
};

src/Components/Dropdown/Dropdown.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { useOnClickOutside } from "Hooks/useClickOutside";
44
import { RefObject, useRef } from "react";
55
import { vi } from "vitest";
66

7-
import Icon from "Components/Icon";
8-
97
import Dropdown from "./";
108

119
describe("Dropdown Component", () => {
@@ -37,7 +35,10 @@ describe("Dropdown Component", () => {
3735
options={[
3836
{
3937
value: "foo",
40-
icon: <Icon iconName='IconShare' className='yl:w-4' />
38+
icon: {
39+
iconName: "IconShare",
40+
className: "yl:w-4"
41+
}
4142
}
4243
]}
4344
/>

src/Components/Dropdown/types.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { OptionsGeneric } from "@popperjs/core";
22
import { PopperOffsetsModifier } from "@popperjs/core/lib/modifiers/popperOffsets";
3-
import { MouseEvent, ReactNode } from "react";
3+
import { MouseEvent } from "react";
44
import { Placement } from "tippy.js";
55

6+
import { IconName } from "Components/Icons/types";
7+
68
export interface IDropdownListItem {
7-
icon?: ReactNode;
9+
icon?: {
10+
iconName: IconName;
11+
className?: string;
12+
dataTestId?: string;
13+
};
814
value?: string;
915
onClick?: (e: MouseEvent, value: string) => void;
1016
setIsOpen: (isOpen: boolean) => void;
@@ -18,7 +24,11 @@ export interface IDropdownProps {
1824
popperOptions?: Partial<OptionsGeneric<PopperOffsetsModifier>>;
1925
placement?: Placement;
2026
options?: {
21-
icon?: React.ReactNode;
27+
icon?: {
28+
iconName: IconName;
29+
className?: string;
30+
dataTestId?: string;
31+
};
2232
value: string;
2333
onClick?: (e: MouseEvent, value: string) => void;
2434
}[];
@@ -27,7 +37,11 @@ export interface IDropdownProps {
2737
export interface IDefaultDropdownProps {
2838
setIsOpen: (isOpen: boolean) => void;
2939
options: {
30-
icon?: ReactNode;
40+
icon?: {
41+
iconName: IconName;
42+
className?: string;
43+
dataTestId?: string;
44+
};
3145
value: string;
3246
onClick?: (e: MouseEvent, value: string) => void;
3347
}[];

src/Components/ItemActions/ItemActions.stories.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,24 @@ export const Default = () => (
1212
}}
1313
/>
1414
);
15+
16+
export const WithCustomOptions = () => (
17+
<ItemActions
18+
item={{ id: "1", name: "Item 1" }}
19+
options={[
20+
{
21+
icon: {
22+
iconName: "Edit1Solid",
23+
className: "yl:w-4"
24+
},
25+
value: "Edit",
26+
onClick: () => {
27+
alert("Share");
28+
}
29+
}
30+
]}
31+
onAction={action => {
32+
alert(action);
33+
}}
34+
/>
35+
);

src/Components/ItemActions/index.tsx

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,65 @@
1-
import { type ReactElement } from "react";
1+
import { MouseEvent, type ReactElement } from "react";
22
import { Placement } from "tippy.js";
33

44
import Dropdown from "Components/Dropdown";
55
import Icon from "Components/Icon";
6+
import { IconName } from "Components/Icons/types";
67

78
import { ItemActionType } from "./types";
89

910
const ItemActions = <T,>({
1011
item,
1112
onAction,
12-
placement
13+
placement,
14+
options = [
15+
{
16+
icon: {
17+
iconName: "IconEdit",
18+
className: "yl:w-4",
19+
dataTestId: "icon-iconedit"
20+
},
21+
value: "edit",
22+
onClick: (e: MouseEvent) => {
23+
e.stopPropagation();
24+
e.preventDefault();
25+
26+
onAction?.(ItemActionType.Edit, item);
27+
}
28+
},
29+
30+
{
31+
icon: {
32+
iconName: "IconDeleteBin",
33+
className: "yl:w-4",
34+
dataTestId: "icon-icondeletebin"
35+
},
36+
value: "delete",
37+
onClick: (e: MouseEvent) => {
38+
e.stopPropagation();
39+
e.preventDefault();
40+
41+
onAction?.(ItemActionType.Delete, item);
42+
}
43+
}
44+
]
1345
}: {
1446
item: T;
47+
options?: {
48+
icon: {
49+
iconName: IconName;
50+
className?: string;
51+
dataTestId?: string;
52+
};
53+
value: string;
54+
onClick: (e: MouseEvent) => void;
55+
}[];
1556
onAction?: (action: ItemActionType, item: T) => void;
1657
placement?: Placement;
1758
}): ReactElement => {
1859
return (
1960
<Dropdown
2061
placement={placement}
21-
options={[
22-
{
23-
icon: (
24-
<Icon
25-
iconName='IconEdit'
26-
className='yl:w-4'
27-
data-testid='icon-iconedit'
28-
/>
29-
),
30-
value: "edit",
31-
onClick: e => {
32-
e.stopPropagation();
33-
e.preventDefault();
34-
35-
onAction?.(ItemActionType.Edit, item);
36-
}
37-
},
38-
39-
{
40-
icon: (
41-
<Icon
42-
iconName='IconDeleteBin'
43-
className='yl:w-4'
44-
data-testid='icon-icondeletebin'
45-
/>
46-
),
47-
value: "delete",
48-
onClick: e => {
49-
e.stopPropagation();
50-
e.preventDefault();
51-
52-
onAction?.(ItemActionType.Delete, item);
53-
}
54-
}
55-
]}
62+
options={options}
5663
buttonContent={
5764
<Icon
5865
iconName='IconDots'

0 commit comments

Comments
 (0)