wip: select
parent
91d26fb0af
commit
c396bc69fb
@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Select, SelectItem } from "./Select";
|
||||
|
||||
const meta: Meta<typeof Select> = {
|
||||
title: "UI/Select",
|
||||
component: Select,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Select>;
|
||||
|
||||
const options = [
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Pear", value: "pear" },
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => (
|
||||
<Select placeholder="Select a fruit" tabIndex={0}>
|
||||
{options.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
),
|
||||
};
|
@ -0,0 +1,79 @@
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
const base = [
|
||||
"inline-flex",
|
||||
"items-center",
|
||||
"justify-between",
|
||||
"border-2",
|
||||
"border-mono-border",
|
||||
"py-1.5",
|
||||
"px-2",
|
||||
"rounded-lg",
|
||||
"focus:outline-none",
|
||||
"focus:border-mono-primary",
|
||||
];
|
||||
|
||||
const viewport = ["p-1"];
|
||||
|
||||
const content = [
|
||||
"relative",
|
||||
"max-h-96",
|
||||
"min-w-[8rem]",
|
||||
"py-1.5",
|
||||
"px-2",
|
||||
"border-2",
|
||||
"border-mono-border",
|
||||
"overflow-hidden",
|
||||
"rounded-lg",
|
||||
"bg-white",
|
||||
|
||||
// Animation
|
||||
"data-[state=open]:animate-in",
|
||||
"data-[state=closed]:animate-out",
|
||||
"data-[state=closed]:fade-out-0",
|
||||
"data-[state=open]:fade-in-0",
|
||||
"data-[state=closed]:zoom-out-95",
|
||||
"data-[state=open]:zoom-in-95",
|
||||
"data-[side=bottom]:slide-in-from-top-2",
|
||||
"data-[side=left]:slide-in-from-right-2",
|
||||
"data-[side=right]:slide-in-from-left-2",
|
||||
"data-[side=top]:slide-in-from-bottom-2",
|
||||
];
|
||||
|
||||
const scroll = [
|
||||
"flex",
|
||||
"cursor-default",
|
||||
"items-center",
|
||||
"justify-center",
|
||||
"py-1",
|
||||
];
|
||||
|
||||
const indicator = [
|
||||
"absolute",
|
||||
"left-0",
|
||||
"inline-flex",
|
||||
"items-center",
|
||||
"justify-center",
|
||||
];
|
||||
|
||||
const selectStyles = cva(base);
|
||||
|
||||
const item = [
|
||||
"relative",
|
||||
"flex",
|
||||
"w-full",
|
||||
"cursor-default",
|
||||
"select-none",
|
||||
"items-center",
|
||||
"py-1.5",
|
||||
"pr-2",
|
||||
"pl-8",
|
||||
"data-[disabled]:pointer-events-none",
|
||||
"data-[disabled]:text-mono-text/50",
|
||||
"focus:outline-none",
|
||||
"focus:border-mono-primary",
|
||||
];
|
||||
|
||||
const itemStyles = cva(item);
|
||||
|
||||
export { selectStyles, itemStyles, viewport, content, indicator, scroll };
|
@ -1,8 +1,62 @@
|
||||
import * as React from "react";
|
||||
import * as $ from "@radix-ui/react-select";
|
||||
import { Label } from "@radix-ui/react-label";
|
||||
import { FaCheck, FaChevronDown, FaChevronUp } from "react-icons/fa";
|
||||
import * as T from "./Select.types";
|
||||
import * as styles from "./Select.styles";
|
||||
import { cx } from "../../utils";
|
||||
import { Box } from "../Box";
|
||||
|
||||
const Select = () => {
|
||||
return <div>Select</div>;
|
||||
};
|
||||
const Select = React.forwardRef<T.SelectElement, T.SelectProps>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
const classes = cx([styles.selectStyles()], className);
|
||||
console.log("classes", classes);
|
||||
return (
|
||||
<Box>
|
||||
<Label htmlFor={"select"}>Select</Label>
|
||||
<Box>
|
||||
<$.Root>
|
||||
<$.Trigger id="select" {...props} className={classes} ref={ref}>
|
||||
<$.Value placeholder={props.placeholder} />
|
||||
<$.Icon className={cx(["ml-2"])} asChild>
|
||||
<FaChevronDown />
|
||||
</$.Icon>
|
||||
</$.Trigger>
|
||||
<$.Portal>
|
||||
<$.Content className={cx([styles.content])} position="popper">
|
||||
<$.ScrollUpButton className={cx([styles.scroll])}>
|
||||
<FaChevronUp />
|
||||
</$.ScrollUpButton>
|
||||
|
||||
export { Select };
|
||||
<$.Viewport className={cx([styles.viewport])}>
|
||||
{children}
|
||||
</$.Viewport>
|
||||
|
||||
<$.ScrollDownButton className={cx([styles.scroll])}>
|
||||
<FaChevronDown />
|
||||
</$.ScrollDownButton>
|
||||
<$.Arrow />
|
||||
</$.Content>
|
||||
</$.Portal>
|
||||
</$.Root>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const SelectItem = React.forwardRef<T.SelectItemElement, T.SelectItemProps>(
|
||||
({ children, className, ...props }, forwardedRef) => {
|
||||
const classes = cx([styles.itemStyles()], className);
|
||||
return (
|
||||
<$.Item {...props} ref={forwardedRef}>
|
||||
<$.ItemText>{children}</$.ItemText>
|
||||
<$.ItemIndicator className={cx([styles.indicator])}>
|
||||
<FaCheck />
|
||||
</$.ItemIndicator>{" "}
|
||||
</$.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Select, SelectItem };
|
||||
|
@ -0,0 +1,32 @@
|
||||
import * as React from "react";
|
||||
import * as $ from "@radix-ui/react-select";
|
||||
import { VariantProps } from "class-variance-authority";
|
||||
import { selectStyles } from "./Select.styles";
|
||||
|
||||
type SelectOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type SelectSection = {
|
||||
label: string;
|
||||
value: SelectOption[];
|
||||
};
|
||||
|
||||
type SelectElement = React.ElementRef<typeof $.Trigger>;
|
||||
|
||||
type SelectProps = React.ComponentPropsWithoutRef<typeof $.Trigger> &
|
||||
VariantProps<typeof selectStyles> & {};
|
||||
|
||||
type SelectItemElement = React.ElementRef<typeof $.Item>;
|
||||
|
||||
type SelectItemProps = React.ComponentPropsWithoutRef<typeof $.Item> & {};
|
||||
|
||||
export {
|
||||
SelectOption,
|
||||
SelectSection,
|
||||
SelectElement,
|
||||
SelectProps,
|
||||
SelectItemElement,
|
||||
SelectItemProps,
|
||||
};
|
Loading…
Reference in New Issue