wip: select

main
Juan Olvera 9 months ago
parent 91d26fb0af
commit c396bc69fb

@ -735,14 +735,6 @@ select {
right: 0px; right: 0px;
} }
.right-4 {
right: 1rem;
}
.top-4 {
top: 1rem;
}
.top-1\/2 { .top-1\/2 {
top: 50%; top: 50%;
} }
@ -751,30 +743,14 @@ select {
left: 50%; left: 50%;
} }
.top-1 { .top-3 {
top: 0.25rem; top: 0.75rem;
}
.right-2 {
right: 0.5rem;
}
.right-1 {
right: 0.25rem;
}
.top-2 {
top: 0.5rem;
} }
.right-3 { .right-3 {
right: 0.75rem; right: 0.75rem;
} }
.top-3 {
top: 0.75rem;
}
.isolate { .isolate {
isolation: isolate; isolation: isolate;
} }
@ -795,6 +771,10 @@ select {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.ml-2 {
margin-left: 0.5rem;
}
.box-border { .box-border {
box-sizing: border-box; box-sizing: border-box;
} }
@ -811,10 +791,6 @@ select {
display: inline-flex; display: inline-flex;
} }
.grid {
display: grid;
}
.h-full { .h-full {
height: 100%; height: 100%;
} }
@ -823,24 +799,32 @@ select {
height: 2px; height: 2px;
} }
.w-full { .h-10 {
width: 100%; height: 2.5rem;
} }
.w-96 { .max-h-96 {
width: 24rem; max-height: 24rem;
} }
.w-56 { .w-56 {
width: 14rem; width: 14rem;
} }
.w-full {
width: 100%;
}
.w-96 {
width: 24rem;
}
.min-w-0 { .min-w-0 {
min-width: 0px; min-width: 0px;
} }
.max-w-lg { .min-w-\[8rem\] {
max-width: 32rem; min-width: 8rem;
} }
.-translate-x-2\/4 { .-translate-x-2\/4 {
@ -853,28 +837,28 @@ select {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-x-\[-50\%\] { .-translate-x-1\/2 {
--tw-translate-x: -50%; --tw-translate-x: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.translate-y-\[-50\%\] { .-translate-y-1\/2 {
--tw-translate-y: -50%; --tw-translate-y: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.-translate-x-1\/2 { .transform {
--tw-translate-x: -50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.-translate-y-1\/2 { .cursor-default {
--tw-translate-y: -50%; cursor: default;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
} }
.transform { .select-none {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -webkit-user-select: none;
-moz-user-select: none;
user-select: none;
} }
.items-center { .items-center {
@ -889,10 +873,6 @@ select {
justify-content: space-between; justify-content: space-between;
} }
.gap-4 {
gap: 1rem;
}
.gap-x-2 { .gap-x-2 {
-moz-column-gap: 0.5rem; -moz-column-gap: 0.5rem;
column-gap: 0.5rem; column-gap: 0.5rem;
@ -934,30 +914,26 @@ select {
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.rounded-sm { .rounded-full {
border-radius: 0.125rem; border-radius: 9999px;
} }
.rounded-md { .rounded-md {
border-radius: 0.375rem; border-radius: 0.375rem;
} }
.rounded-full {
border-radius: 9999px;
}
.border-2 { .border-2 {
border-width: 2px; border-width: 2px;
} }
.border {
border-width: 1px;
}
.border-0 { .border-0 {
border-width: 0px; border-width: 0px;
} }
.border {
border-width: 1px;
}
.border-mono-border { .border-mono-border {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity)); border-color: rgb(209 213 219 / var(--tw-border-opacity));
@ -988,10 +964,6 @@ select {
background-color: rgb(209 213 219 / var(--tw-bg-opacity)); background-color: rgb(209 213 219 / var(--tw-bg-opacity));
} }
.bg-black\/80 {
background-color: rgb(0 0 0 / 0.8);
}
.bg-black { .bg-black {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity)); background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@ -1005,14 +977,14 @@ select {
--tw-bg-opacity: 0.5; --tw-bg-opacity: 0.5;
} }
.p-0 {
padding: 0px;
}
.p-1 { .p-1 {
padding: 0.25rem; padding: 0.25rem;
} }
.p-0 {
padding: 0px;
}
.p-2 { .p-2 {
padding: 0.5rem; padding: 0.5rem;
} }
@ -1102,6 +1074,14 @@ select {
padding-right: 0.75rem; padding-right: 0.75rem;
} }
.pr-2 {
padding-right: 0.5rem;
}
.pl-8 {
padding-left: 2rem;
}
.text-left { .text-left {
text-align: left; text-align: left;
} }
@ -1162,13 +1142,9 @@ select {
opacity: 0; opacity: 0;
} }
.opacity-70 { .shadow-md {
opacity: 0.7; --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
} --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
} }
@ -1177,14 +1153,18 @@ select {
outline-offset: 2px; outline-offset: 2px;
} }
.transition-opacity { @keyframes enter {
transition-property: opacity; from {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); opacity: var(--tw-enter-opacity, 1);
transition-duration: 150ms; transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));
}
} }
.duration-200 { @keyframes exit {
transition-duration: 200ms; to {
opacity: var(--tw-exit-opacity, 1);
transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));
}
} }
html { html {
@ -1211,8 +1191,14 @@ html {
background-color: rgb(63 63 70 / var(--tw-bg-opacity)); background-color: rgb(63 63 70 / var(--tw-bg-opacity));
} }
.hover\:opacity-100:hover { .hover\:bg-mono-hover:hover {
opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(156 163 175 / var(--tw-bg-opacity));
}
.hover\:bg-mono-primary:hover {
--tw-bg-opacity: 1;
background-color: rgb(39 39 42 / var(--tw-bg-opacity));
} }
.focus\:border-mono-primary:focus { .focus\:border-mono-primary:focus {
@ -1256,10 +1242,22 @@ html {
--tw-ring-offset-width: 2px; --tw-ring-offset-width: 2px;
} }
.disabled\:pointer-events-none:disabled { .disabled\:cursor-not-allowed:disabled {
cursor: not-allowed;
}
.disabled\:opacity-50:disabled {
opacity: 0.5;
}
.data-\[disabled\]\:pointer-events-none[data-disabled] {
pointer-events: none; pointer-events: none;
} }
.data-\[disabled\]\:text-mono-text\/50[data-disabled] {
color: rgb(107 114 128 / 0.5);
}
.data-\[disabled\]\:opacity-50[data-disabled] { .data-\[disabled\]\:opacity-50[data-disabled] {
opacity: 0.5; opacity: 0.5;
} }
@ -1268,16 +1266,56 @@ html {
outline-style: solid; outline-style: solid;
} }
.data-\[focus\]\:outline-2[data-focus] { .data-\[state\=open\]\:animate-in[data-state=open] {
outline-width: 2px; animation-name: enter;
animation-duration: 150ms;
--tw-enter-opacity: initial;
--tw-enter-scale: initial;
--tw-enter-rotate: initial;
--tw-enter-translate-x: initial;
--tw-enter-translate-y: initial;
} }
.data-\[focus\]\:outline-offset-2[data-focus] { .data-\[state\=closed\]\:animate-out[data-state=closed] {
outline-offset: 2px; animation-name: exit;
animation-duration: 150ms;
--tw-exit-opacity: initial;
--tw-exit-scale: initial;
--tw-exit-rotate: initial;
--tw-exit-translate-x: initial;
--tw-exit-translate-y: initial;
}
.data-\[state\=closed\]\:fade-out-0[data-state=closed] {
--tw-exit-opacity: 0;
}
.data-\[state\=open\]\:fade-in-0[data-state=open] {
--tw-enter-opacity: 0;
}
.data-\[state\=closed\]\:zoom-out-95[data-state=closed] {
--tw-exit-scale: .95;
}
.data-\[state\=open\]\:zoom-in-95[data-state=open] {
--tw-enter-scale: .95;
}
.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom] {
--tw-enter-translate-y: -0.5rem;
} }
.data-\[focus\]\:outline-blue-500[data-focus] { .data-\[side\=left\]\:slide-in-from-right-2[data-side=left] {
outline-color: #3b82f6; --tw-enter-translate-x: 0.5rem;
}
.data-\[side\=right\]\:slide-in-from-left-2[data-side=right] {
--tw-enter-translate-x: -0.5rem;
}
.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top] {
--tw-enter-translate-y: 0.5rem;
} }
@media (prefers-reduced-motion: no-preference) { @media (prefers-reduced-motion: no-preference) {
@ -1293,10 +1331,6 @@ html {
} }
@media (min-width: 640px) { @media (min-width: 640px) {
.sm\:rounded-lg {
border-radius: 0.5rem;
}
.sm\:px-6 { .sm\:px-6 {
padding-left: 1.5rem; padding-left: 1.5rem;
padding-right: 1.5rem; padding-right: 1.5rem;

34
package-lock.json generated

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.4", "@radix-ui/react-dropdown-menu": "^2.0.4",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-primitive": "^1.0.3", "@radix-ui/react-primitive": "^1.0.3",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.0.0",
@ -60,6 +61,7 @@
"storybook": "^7.6.7", "storybook": "^7.6.7",
"tailwind-merge": "^1.11.0", "tailwind-merge": "^1.11.0",
"tailwindcss": "^3.2.4", "tailwindcss": "^3.2.4",
"tailwindcss-animate": "^1.0.7",
"ts-jest": "^29.0.5", "ts-jest": "^29.0.5",
"tsup": "^6.5.0", "tsup": "^6.5.0",
"typescript": "^5.1.6", "typescript": "^5.1.6",
@ -4259,6 +4261,29 @@
"react": "^16.8 || ^17.0 || ^18.0" "react": "^16.8 || ^17.0 || ^18.0"
} }
}, },
"node_modules/@radix-ui/react-label": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
"integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-menu": { "node_modules/@radix-ui/react-menu": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.4.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.4.tgz",
@ -24263,6 +24288,15 @@
"postcss": "^8.0.9" "postcss": "^8.0.9"
} }
}, },
"node_modules/tailwindcss-animate": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
"integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
"dev": true,
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders"
}
},
"node_modules/tailwindcss/node_modules/color-name": { "node_modules/tailwindcss/node_modules/color-name": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",

@ -71,6 +71,7 @@
"storybook": "^7.6.7", "storybook": "^7.6.7",
"tailwind-merge": "^1.11.0", "tailwind-merge": "^1.11.0",
"tailwindcss": "^3.2.4", "tailwindcss": "^3.2.4",
"tailwindcss-animate": "^1.0.7",
"ts-jest": "^29.0.5", "ts-jest": "^29.0.5",
"tsup": "^6.5.0", "tsup": "^6.5.0",
"typescript": "^5.1.6", "typescript": "^5.1.6",
@ -79,6 +80,7 @@
"dependencies": { "dependencies": {
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.4", "@radix-ui/react-dropdown-menu": "^2.0.4",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-primitive": "^1.0.3", "@radix-ui/react-primitive": "^1.0.3",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.0.0",

@ -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 React from "react";
import * as $ from "@radix-ui/react-select"; 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 = () => { const Select = React.forwardRef<T.SelectElement, T.SelectProps>(
return <div>Select</div>; ({ 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,
};

@ -28,6 +28,9 @@ module.exports = {
"mono-text": { "mono-text": {
DEFAULT: colors.gray["500"], DEFAULT: colors.gray["500"],
}, },
"mono-hover": {
DEFAULT: colors.gray[400],
},
"mono-rounded": { "mono-rounded": {
DEFAULT: defaultTheme.borderRadius["lg"], DEFAULT: defaultTheme.borderRadius["lg"],
}, },
@ -38,5 +41,5 @@ module.exports = {
}, },
}, },
}, },
plugins: [require("@tailwindcss/forms")], plugins: [require("@tailwindcss/forms"), require("tailwindcss-animate")],
}; };

Loading…
Cancel
Save