This commit is contained in:
DCCONSTRUCTIONS
2026-04-18 18:39:25 +03:00
commit 3ba092b60c
4944 changed files with 497564 additions and 0 deletions
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import type React from "react";
export const iconButtonVariants = cva(
"inline-flex aspect-square items-center justify-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none disabled:pointer-events-none",
{
variants: {
variant: {
primary:
"bg-accent-primary text-on-color hover:bg-accent-primary-hover focus:bg-accent-primary-active active:bg-accent-primary-active disabled:bg-layer-disabled disabled:text-on-color-disabled",
"error-fill":
"bg-danger-primary text-on-color hover:bg-danger-primary-hover focus:bg-danger-primary-active active:bg-danger-primary-active disabled:bg-layer-disabled disabled:text-disabled",
"error-outline":
"border border-danger-strong bg-layer-2 text-danger-primary hover:bg-danger-subtle focus:bg-danger-subtle-hover active:bg-danger-subtle-hover disabled:border-subtle-1 disabled:bg-layer-2 disabled:text-disabled",
secondary:
"border border-strong bg-layer-2 text-secondary shadow-raised-100 hover:bg-layer-2-hover focus:bg-layer-2-active active:bg-layer-2-active disabled:border-subtle-1 disabled:bg-layer-transparent disabled:text-disabled",
tertiary:
"bg-layer-3 text-secondary hover:bg-layer-3-hover focus:bg-layer-3-active active:bg-layer-3-active disabled:bg-layer-transparent disabled:text-disabled",
ghost:
"bg-layer-transparent text-secondary hover:bg-layer-transparent-hover focus:bg-layer-transparent-active active:bg-layer-transparent-active disabled:bg-layer-transparent disabled:text-disabled",
},
size: {
sm: "size-5 rounded-sm",
base: "size-6 rounded-md",
lg: "size-7 rounded-md",
xl: "size-8 rounded-md",
},
},
defaultVariants: {
variant: "primary",
size: "base",
},
}
);
type IconButtonPropsWithChildren = React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof iconButtonVariants> & {
icon: React.FC<{ className?: string }>;
loading?: boolean;
iconClassName?: string;
};
export type IconButtonProps = Omit<IconButtonPropsWithChildren, "children">;
export function getIconButtonStyling(
variant: NonNullable<IconButtonProps["variant"]>,
size: NonNullable<IconButtonProps["size"]>
): string {
return iconButtonVariants({ variant, size });
}
@@ -0,0 +1,180 @@
/**
* 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 { IconButton } from "./icon-button";
const icon = () => (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12 5v14m-7-7h14" />
</svg>
);
const meta = {
title: "Components/IconButton",
component: IconButton,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
args: {
icon,
},
} satisfies Meta<typeof IconButton>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
icon,
},
};
export const Primary: Story = {
args: {
variant: "primary",
icon,
},
};
export const ErrorFill: Story = {
args: {
variant: "error-fill",
icon,
},
};
export const ErrorOutline: Story = {
args: {
variant: "error-outline",
icon,
},
};
export const Secondary: Story = {
args: {
variant: "secondary",
icon,
},
};
export const Tertiary: Story = {
args: {
variant: "tertiary",
icon,
},
};
export const Ghost: Story = {
args: {
variant: "ghost",
icon,
},
};
export const Small: Story = {
args: {
size: "sm",
icon,
},
};
export const Base: Story = {
args: {
size: "base",
icon,
},
};
export const Large: Story = {
args: {
size: "lg",
icon,
},
};
export const ExtraLarge: Story = {
args: {
size: "xl",
icon,
},
};
export const Loading: Story = {
args: {
loading: true,
icon,
},
};
export const Disabled: Story = {
args: {
disabled: true,
icon,
},
};
export const AllVariants: Story = {
render() {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-16 font-semibold">Primary Variants</h3>
<div className="flex flex-wrap gap-2">
<IconButton variant="primary" icon={icon} />
<IconButton variant="error-fill" icon={icon} />
<IconButton variant="error-outline" icon={icon} />
<IconButton variant="secondary" icon={icon} />
<IconButton variant="tertiary" icon={icon} />
<IconButton variant="ghost" icon={icon} />
</div>
</div>
</div>
);
},
};
export const AllSizes: Story = {
render() {
return (
<div className="space-y-4">
<div className="flex items-center gap-2">
<IconButton size="sm" icon={icon} />
<IconButton size="base" icon={icon} />
<IconButton size="lg" icon={icon} />
<IconButton size="xl" icon={icon} />
</div>
</div>
);
},
};
export const AllStates: Story = {
render() {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-16 font-semibold">Button States</h3>
<div className="flex flex-wrap gap-2">
<IconButton icon={icon} />
<IconButton loading icon={icon} />
<IconButton disabled icon={icon} />
</div>
</div>
</div>
);
},
};
@@ -0,0 +1,52 @@
/**
* 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";
import type { IconButtonProps } from "./helper";
import { iconButtonVariants } from "./helper";
const IconButton = React.forwardRef(function IconButton(
props: IconButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>
) {
const {
variant = "primary",
size = "base",
className = "",
type = "button",
loading = false,
disabled = false,
icon: Icon,
iconClassName = "",
...rest
} = props;
return (
<button
ref={ref}
type={type}
className={cn(iconButtonVariants({ variant, size }), className)}
disabled={disabled || loading}
{...rest}
>
<Icon
className={cn(
{
"size-3.5": size === "sm",
"size-4": size === "base" || size === "lg",
"size-5": size === "xl",
},
iconClassName
)}
/>
</button>
);
});
IconButton.displayName = "plane-ui-icon-button";
export { IconButton };
@@ -0,0 +1,9 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
export { IconButton } from "./icon-button";
export { getIconButtonStyling } from "./helper";
export type { IconButtonProps } from "./helper";