base
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
export { Pill, EPillVariant, EPillSize } from "./pill";
|
||||
export type { PillProps } from "./pill";
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { Pill, EPillVariant, EPillSize } from "./pill";
|
||||
|
||||
const meta = {
|
||||
title: "Components/Pill",
|
||||
component: Pill,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
children: "Default",
|
||||
},
|
||||
} satisfies Meta<typeof Pill>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
variant: EPillVariant.PRIMARY,
|
||||
children: "Primary",
|
||||
},
|
||||
};
|
||||
|
||||
export const Success: Story = {
|
||||
args: {
|
||||
variant: EPillVariant.SUCCESS,
|
||||
children: "Success",
|
||||
},
|
||||
};
|
||||
|
||||
export const Warning: Story = {
|
||||
args: {
|
||||
variant: EPillVariant.WARNING,
|
||||
children: "Warning",
|
||||
},
|
||||
};
|
||||
|
||||
export const Error: Story = {
|
||||
args: {
|
||||
variant: EPillVariant.ERROR,
|
||||
children: "Error",
|
||||
},
|
||||
};
|
||||
|
||||
export const Info: Story = {
|
||||
args: {
|
||||
variant: EPillVariant.INFO,
|
||||
children: "Info",
|
||||
},
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
args: {
|
||||
size: EPillSize.SM,
|
||||
children: "Small",
|
||||
},
|
||||
};
|
||||
|
||||
export const Medium: Story = {
|
||||
args: {
|
||||
size: EPillSize.MD,
|
||||
children: "Medium",
|
||||
},
|
||||
};
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
size: EPillSize.LG,
|
||||
children: "Large",
|
||||
},
|
||||
};
|
||||
|
||||
export const AllVariants: Story = {
|
||||
render() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Pill variant={EPillVariant.DEFAULT}>Default</Pill>
|
||||
<Pill variant={EPillVariant.PRIMARY}>Primary</Pill>
|
||||
<Pill variant={EPillVariant.SUCCESS}>Success</Pill>
|
||||
<Pill variant={EPillVariant.WARNING}>Warning</Pill>
|
||||
<Pill variant={EPillVariant.ERROR}>Error</Pill>
|
||||
<Pill variant={EPillVariant.INFO}>Info</Pill>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const AllSizes: Story = {
|
||||
render() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Pill size={EPillSize.SM}>Small</Pill>
|
||||
<Pill size={EPillSize.MD}>Medium</Pill>
|
||||
<Pill size={EPillSize.LG}>Large</Pill>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const WithNumbers: Story = {
|
||||
render() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Pill variant={EPillVariant.PRIMARY}>3</Pill>
|
||||
<Pill variant={EPillVariant.SUCCESS}>12</Pill>
|
||||
<Pill variant={EPillVariant.WARNING}>99+</Pill>
|
||||
<Pill variant={EPillVariant.ERROR}>!</Pill>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const StatusExamples: Story = {
|
||||
render() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-13 font-medium">Task Status</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Pill variant={EPillVariant.DEFAULT}>Draft</Pill>
|
||||
<Pill variant={EPillVariant.WARNING}>In Progress</Pill>
|
||||
<Pill variant={EPillVariant.INFO}>In Review</Pill>
|
||||
<Pill variant={EPillVariant.SUCCESS}>Completed</Pill>
|
||||
<Pill variant={EPillVariant.ERROR}>Blocked</Pill>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "../utils";
|
||||
|
||||
export enum EPillVariant {
|
||||
DEFAULT = "default",
|
||||
PRIMARY = "primary",
|
||||
SUCCESS = "success",
|
||||
WARNING = "warning",
|
||||
ERROR = "error",
|
||||
INFO = "info",
|
||||
}
|
||||
|
||||
export enum EPillSize {
|
||||
SM = "sm",
|
||||
MD = "md",
|
||||
LG = "lg",
|
||||
XS = "xs",
|
||||
}
|
||||
|
||||
export enum ERadius {
|
||||
SQUARE = "square",
|
||||
CIRCLE = "circle",
|
||||
}
|
||||
|
||||
export type TRadius = ERadius.SQUARE | ERadius.CIRCLE;
|
||||
|
||||
export type TPillVariant =
|
||||
| EPillVariant.DEFAULT
|
||||
| EPillVariant.PRIMARY
|
||||
| EPillVariant.SUCCESS
|
||||
| EPillVariant.WARNING
|
||||
| EPillVariant.ERROR
|
||||
| EPillVariant.INFO;
|
||||
export type TPillSize = EPillSize.SM | EPillSize.MD | EPillSize.LG | EPillSize.XS;
|
||||
|
||||
export interface PillProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
variant?: TPillVariant;
|
||||
size?: TPillSize;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
radius?: TRadius;
|
||||
}
|
||||
|
||||
const pillVariants = {
|
||||
[EPillVariant.DEFAULT]: "bg-surface-2 text-secondary border border-subtle-1",
|
||||
[EPillVariant.PRIMARY]: "bg-accent-primary/10 text-accent-primary border border-accent-strong/20",
|
||||
[EPillVariant.SUCCESS]: "bg-green-50 text-success-primary border border-success-subtle",
|
||||
[EPillVariant.WARNING]: "bg-amber-50 text-amber-700 border border-amber-200",
|
||||
[EPillVariant.ERROR]: "bg-red-50 text-danger-primary border border-danger-subtle",
|
||||
[EPillVariant.INFO]: "bg-blue-50 text-blue-700 border border-blue-200",
|
||||
};
|
||||
|
||||
const pillSizes = {
|
||||
[EPillSize.XS]: "px-1.5 py-0.5 text-11",
|
||||
[EPillSize.SM]: "px-2 py-0.5 text-11",
|
||||
[EPillSize.MD]: "px-2.5 py-1 text-13",
|
||||
[EPillSize.LG]: "px-3 py-1.5 text-14",
|
||||
};
|
||||
|
||||
const pillRadius = {
|
||||
[ERadius.SQUARE]: "rounded",
|
||||
[ERadius.CIRCLE]: "rounded-full",
|
||||
};
|
||||
|
||||
const Pill = React.forwardRef(function Pill(
|
||||
{
|
||||
variant = EPillVariant.DEFAULT,
|
||||
size = EPillSize.MD,
|
||||
radius = ERadius.CIRCLE,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: PillProps,
|
||||
ref: React.ForwardedRef<HTMLSpanElement>
|
||||
) {
|
||||
return (
|
||||
<span
|
||||
ref={ref}
|
||||
className={cn(
|
||||
// Base styles
|
||||
"inline-flex items-center justify-center rounded-full font-medium whitespace-nowrap",
|
||||
// Variant styles
|
||||
pillVariants[variant],
|
||||
// Size styles
|
||||
pillSizes[size],
|
||||
// Radius styles
|
||||
pillRadius[radius],
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
Pill.displayName = "Pill";
|
||||
|
||||
export { Pill };
|
||||
Reference in New Issue
Block a user