Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
feat: add Select component
Browse files Browse the repository at this point in the history
  • Loading branch information
MikaelSiidorow committed May 30, 2023
1 parent d2586f7 commit 7f2cadf
Show file tree
Hide file tree
Showing 6 changed files with 569 additions and 12 deletions.
29 changes: 29 additions & 0 deletions lib/components/Select/Select.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryFn } from "@storybook/react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/Select";

/**
* ```typescript
* import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@tietokilta/ui";
* ```
*/
export default {
title: "Select",
component: Select
} satisfies Meta<typeof Select>;

const Template: StoryFn<typeof Select> = (args) => (
<Select {...args}>
<SelectTrigger>
<SelectValue placeholder="Year" />
</SelectTrigger>
<SelectContent>
{Array.from({ length: 37 }).map((_, i) => (
<SelectItem value={(2023 - i).toString()} key={i} disabled={i > 1 && i < 4}>
{2023 - i}
</SelectItem>
))}
</SelectContent>
</Select>
);

export const Primary = Template.bind({});
15 changes: 15 additions & 0 deletions lib/components/Select/Select.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { render, screen } from "@testing-library/react";
import { Select, SelectTrigger, SelectValue } from "~/components/Select";

describe("Select", () => {
it("should display placeholder text", () => {
render(
<Select>
<SelectTrigger>
<SelectValue placeholder="Placeholder" />
</SelectTrigger>
</Select>
);
expect(screen.getByRole("combobox")).toHaveTextContent("Placeholder");
});
});
75 changes: 75 additions & 0 deletions lib/components/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as SelectPrimitive from "@radix-ui/react-select";
import { ChevronDown, ChevronUp } from "lucide-react";
import * as React from "react";
import { cn } from "~/utils";

const Select = SelectPrimitive.Root;
const SelectValue = SelectPrimitive.Value;

const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"focus-visible:outline-3 inline-flex items-center justify-center gap-1 rounded-lg border-2 border-gray-900 bg-gray-100 px-2 py-1 drop-shadow-[4px_4px_black] hover:bg-gray-300 focus-visible:bg-gray-200 focus-visible:outline focus-visible:outline-gray-900 data-[state=open]:rounded-b-none data-[placeholder]:text-gray-600",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;

const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"rounded-lg border-2 border-gray-900 bg-gray-100 p-2 drop-shadow-[4px_4px_black]",
className
)}
{...props}
>
<SelectPrimitive.ScrollUpButton
className={"flex h-6 cursor-default items-center justify-center bg-gray-100 text-gray-900"}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
<SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>
<SelectPrimitive.ScrollDownButton
className={"flex h-6 cursor-default items-center justify-center bg-gray-100 text-gray-900"}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;

const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"flex select-none items-center gap-1 px-2 data-[disabled]:pointer-events-none data-[highlighted]:data-[state=unchecked]:bg-gray-300 data-[state=checked]:bg-gray-300 data-[state=checked]:font-medium data-[disabled]:text-gray-400 data-[highlighted]:outline-none",
className
)}
{...props}
>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;

export { Select, SelectContent, SelectItem, SelectValue, SelectTrigger };
1 change: 1 addition & 0 deletions lib/main.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as Button, type ButtonProps } from "~/components/Button";
export * as Select from "~/components/Select";
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
}
},
"dependencies": {
"@radix-ui/react-select": "^1.2.1",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"lucide-react": "^0.221.0",
"tailwind-merge": "^1.12.0"
},
"peerDependencies": {
Expand Down
Loading

0 comments on commit 7f2cadf

Please sign in to comment.