Skip to content

Commit e10d105

Browse files
authored
feat(react): add DropdownState component (#42)
1 parent 2185a69 commit e10d105

File tree

6 files changed

+118
-1
lines changed

6 files changed

+118
-1
lines changed

js/react/lib/components/badge/badge.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const Badge = withAs(
2020
<Component
2121
{...rest}
2222
className={cn([
23-
"text-paragraph-2 flex items-center gap-1 rounded-full border-[0.8px] border-black px-2",
23+
"text-paragraph-2 flex w-fit items-center gap-1 rounded-full border-[0.8px] border-black px-2",
2424
BADGE_VARIANTS[variant],
2525
BADGE_TYPE[type],
2626
"desktop:text-[12px] text-[10px]",
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { cn } from "@/utils/tw-merge";
2+
import { BADGE_TEXT, BadgeVariants } from "../badge/badge.const";
3+
import { useState } from "react";
4+
import { ArrowDown, ArrowUp } from "@/icons";
5+
import { Badge } from "../badge";
6+
import { DROPDOWN_OPTIONS, DROPDOWN_STATUS_VARIANTS } from "./dropdown.const";
7+
8+
type DropdownStateProps = {
9+
value: BadgeVariants;
10+
onChange: (value: BadgeVariants) => void;
11+
};
12+
13+
export const DropdownState = ({ value, onChange }: DropdownStateProps) => {
14+
const [open, setOpen] = useState(false);
15+
16+
const handleOpen = () => setOpen(status => !status);
17+
18+
const handleSelect = (val: BadgeVariants) => {
19+
onChange(val);
20+
setOpen(false);
21+
};
22+
23+
const Icon = open ? ArrowUp : ArrowDown;
24+
25+
return (
26+
<div className="relative grid w-fit">
27+
<button
28+
onClick={handleOpen}
29+
className={cn([
30+
"shadow-rb-black text-paragraph-2 flex h-6 items-center gap-1 overflow-hidden rounded-sm border border-black",
31+
DROPDOWN_STATUS_VARIANTS[value],
32+
"text-[12px]",
33+
])}
34+
>
35+
<div className="ml-2 size-1 rounded-full" />
36+
<span className="mr-2">{BADGE_TEXT[value]}</span>
37+
<Icon
38+
className={cn([
39+
"size-6 rounded-r-sm border-l border-l-black",
40+
"bg-white text-black",
41+
"dark:bg-dark dark:text-neutral-50",
42+
])}
43+
/>
44+
</button>
45+
<div
46+
className={cn([
47+
"absolute left-0 top-full mt-2 w-full transition duration-200",
48+
open ? "visible opacity-100" : "invisible opacity-0",
49+
])}
50+
>
51+
{open && (
52+
<ul className="options shadow-rb-black dark:bg-dark grid gap-1.5 rounded-sm border border-black bg-white px-2 py-1.5 transition">
53+
{DROPDOWN_OPTIONS.map(opt => (
54+
<li
55+
key={opt.value}
56+
className="option cursor-pointer"
57+
onClick={() => handleSelect(opt.value)}
58+
>
59+
<Badge type="text" variant={opt.value} />
60+
</li>
61+
))}
62+
</ul>
63+
)}
64+
</div>
65+
</div>
66+
);
67+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { BadgeVariants } from "../badge/badge.const";
2+
3+
export const DROPDOWN_STATUS_VARIANTS = {
4+
completed: [
5+
"bg-success-100 text-success-600 [&>div]:bg-success-600",
6+
"dark:bg-success-900 dark:text-success-400 dark:[&>div]:bg-success-400",
7+
],
8+
reading: [
9+
"bg-warning-100 text-warning-500 [&>div]:bg-warning-500",
10+
"dark:bg-warning-950 dark:text-warning-300 [&>div]:bg-warning-300",
11+
],
12+
pending: [
13+
"bg-error-100 text-error-600 [&>div]:bg-error-600",
14+
"dark:bg-error-950 dark:text-error-300 [&>div]:bg-error-300",
15+
],
16+
unread: [
17+
"bg-neutral-100 text-neutral-500 [&>div]:bg-neutral-500",
18+
"dark:bg-neutral-950 dark:text-neutral-300 [&>div]:bg-neutral-300",
19+
],
20+
};
21+
22+
export type Option = {
23+
label: string;
24+
value: BadgeVariants;
25+
};
26+
27+
export const DROPDOWN_OPTIONS: Array<Option> = [
28+
{ label: "Completo", value: "completed" },
29+
{ label: "Leyendo", value: "reading" },
30+
{ label: "Pendiente", value: "pending" },
31+
{ label: "No leído", value: "unread" },
32+
];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./dropdown.component";

js/react/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export * from "./components/avatar";
88
export * from "./components/collaborators";
99
export * from "./components/radio";
1010
export * from "./components/badge";
11+
export * from "./components/dropdown";
1112
export * from "./icons";

js/react/showcase/App.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Collaborators,
1111
Radio,
1212
Badge,
13+
DropdownState,
1314
} from "@rustlanges/react";
1415
import { ShowComponent } from "./ShowComponent";
1516

@@ -242,6 +243,21 @@ export function App() {
242243
},
243244
}}
244245
/>
246+
<ShowComponent
247+
component={DropdownState}
248+
title="Dropdown State"
249+
propsDef={{
250+
onChange: {
251+
type: "callback",
252+
default: console.log,
253+
},
254+
value: {
255+
type: "string",
256+
options: ["completed", "pending", "reading", "unread"],
257+
default: "completed",
258+
},
259+
}}
260+
/>
245261
</div>
246262
);
247263
}

0 commit comments

Comments
 (0)