diff --git a/apps/ui-kit/.storybook/preview-head.html b/apps/ui-kit/.storybook/preview-head.html index 92c1aef28a0..b0c19050920 100644 --- a/apps/ui-kit/.storybook/preview-head.html +++ b/apps/ui-kit/.storybook/preview-head.html @@ -2,10 +2,10 @@ diff --git a/apps/ui-kit/package.json b/apps/ui-kit/package.json index 34508ca4016..234242b033f 100644 --- a/apps/ui-kit/package.json +++ b/apps/ui-kit/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@fontsource/inter": "^5.0.17", + "classnames": "^2.5.1", "lodash.merge": "^4.6.2", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/apps/ui-kit/postcss.config.js b/apps/ui-kit/postcss.config.js index 0fa3edd478d..5ec04be2c17 100644 --- a/apps/ui-kit/postcss.config.js +++ b/apps/ui-kit/postcss.config.js @@ -3,6 +3,7 @@ module.exports = { plugins: { + 'tailwindcss/nesting': {}, tailwindcss: {}, autoprefixer: {}, }, diff --git a/apps/ui-kit/src/lib/components/Button.tsx b/apps/ui-kit/src/lib/components/Button.tsx deleted file mode 100644 index 2352a80effe..00000000000 --- a/apps/ui-kit/src/lib/components/Button.tsx +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import React from 'react'; - -export interface ButtonProps { - label: string; -} - -export function Button({ label }: ButtonProps): React.JSX.Element { - return ( - - ); -} diff --git a/apps/ui-kit/src/lib/components/atoms/button/Button.tsx b/apps/ui-kit/src/lib/components/atoms/button/Button.tsx new file mode 100644 index 00000000000..bd7bd268725 --- /dev/null +++ b/apps/ui-kit/src/lib/components/atoms/button/Button.tsx @@ -0,0 +1,72 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import React from 'react'; +import { ButtonSize, ButtonType } from './button.enums'; +import { + PADDINGS, + PADDINGS_ONLY_ICON, + BACKGROUND_COLORS, + TEXT_COLORS, + TEXT_CLASSES, + TEXT_COLOR_DISABLED, + DISABLED_BACKGROUND_COLORS, +} from './button.classes'; +import cx from 'classnames'; + +interface ButtonProps { + /** + * The size of the button. + */ + size?: ButtonSize; + /** + * The type of the button + */ + type?: ButtonType; + /** + * The text of the button. + */ + text?: string; + /** + The icon of the button + */ + icon?: React.ReactNode; + /** + * The button is disabled or not. + */ + disabled?: boolean; + /** + * The onClick event of the button. + */ + onClick?: (e: React.MouseEvent) => void; +} + +export function Button({ + icon, + text, + disabled, + onClick, + size = ButtonSize.Medium, + type = ButtonType.Primary, +}: ButtonProps): React.JSX.Element { + const paddingClasses = icon && !text ? PADDINGS_ONLY_ICON[size] : PADDINGS[size]; + const textSizes = TEXT_CLASSES[size]; + const backgroundColors = disabled ? DISABLED_BACKGROUND_COLORS[type] : BACKGROUND_COLORS[type]; + const textColors = disabled ? TEXT_COLOR_DISABLED[type] : TEXT_COLORS[type]; + return ( + + ); +} diff --git a/apps/ui-kit/src/lib/components/atoms/button/button.classes.ts b/apps/ui-kit/src/lib/components/atoms/button/button.classes.ts new file mode 100644 index 00000000000..8fe776c82f7 --- /dev/null +++ b/apps/ui-kit/src/lib/components/atoms/button/button.classes.ts @@ -0,0 +1,53 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { ButtonSize, ButtonType } from './button.enums'; + +export const PADDINGS: Record = { + [ButtonSize.Small]: 'px-md py-xs', + [ButtonSize.Medium]: 'px-md py-sm', +}; + +export const PADDINGS_ONLY_ICON: Record = { + [ButtonSize.Small]: 'p-xs', + [ButtonSize.Medium]: 'p-sm', +}; + +export const BACKGROUND_COLORS: Record = { + [ButtonType.Primary]: 'bg-primary-30', + [ButtonType.Secondary]: 'bg-neutral-90 dark:bg-neutral-20', + [ButtonType.Ghost]: 'bg-transparent', + [ButtonType.Outlined]: 'bg-transparent border border-neutral-50', + [ButtonType.Destructive]: 'bg-error-90', +}; + +export const DISABLED_BACKGROUND_COLORS: Record = { + [ButtonType.Primary]: 'bg-neutral-80 dark:bg-neutral-30', + [ButtonType.Secondary]: 'bg-neutral-90 dark:bg-neutral-20', + [ButtonType.Ghost]: 'bg-transparent', + [ButtonType.Outlined]: 'bg-transparent border border-neutral-50', + [ButtonType.Destructive]: 'bg-error-90', +}; + +const DEFAULT_TEXT_COLORS: string = 'text-neutral-10 dark:text-neutral-92'; + +export const TEXT_COLORS: Record = { + [ButtonType.Primary]: 'text-primary-100', + [ButtonType.Secondary]: DEFAULT_TEXT_COLORS, + [ButtonType.Ghost]: DEFAULT_TEXT_COLORS, + [ButtonType.Outlined]: DEFAULT_TEXT_COLORS, + [ButtonType.Destructive]: 'text-error-20', +}; + +export const TEXT_CLASSES: Record = { + [ButtonSize.Small]: 'text-label-md', + [ButtonSize.Medium]: 'text-label-lg', +}; + +export const TEXT_COLOR_DISABLED: Record = { + [ButtonType.Primary]: DEFAULT_TEXT_COLORS, + [ButtonType.Secondary]: DEFAULT_TEXT_COLORS, + [ButtonType.Ghost]: DEFAULT_TEXT_COLORS, + [ButtonType.Outlined]: DEFAULT_TEXT_COLORS, + [ButtonType.Destructive]: 'text-error-20', +}; diff --git a/apps/ui-kit/src/lib/components/atoms/button/button.enums.ts b/apps/ui-kit/src/lib/components/atoms/button/button.enums.ts new file mode 100644 index 00000000000..a58bc17534b --- /dev/null +++ b/apps/ui-kit/src/lib/components/atoms/button/button.enums.ts @@ -0,0 +1,15 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export enum ButtonSize { + Small = 'small', + Medium = 'medium', +} + +export enum ButtonType { + Primary = 'primary', + Secondary = 'secondary', + Ghost = 'ghost', + Outlined = 'outlined', + Destructive = 'destructive', +} diff --git a/apps/ui-kit/src/lib/components/atoms/button/index.ts b/apps/ui-kit/src/lib/components/atoms/button/index.ts new file mode 100644 index 00000000000..e0310d5fa03 --- /dev/null +++ b/apps/ui-kit/src/lib/components/atoms/button/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from './Button'; + +export * from './button.enums'; diff --git a/apps/ui-kit/src/lib/components/atoms/index.ts b/apps/ui-kit/src/lib/components/atoms/index.ts new file mode 100644 index 00000000000..55a1be03a07 --- /dev/null +++ b/apps/ui-kit/src/lib/components/atoms/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from './button'; diff --git a/apps/ui-kit/src/lib/components/index.ts b/apps/ui-kit/src/lib/components/index.ts index 72acc235fee..116943b99c3 100644 --- a/apps/ui-kit/src/lib/components/index.ts +++ b/apps/ui-kit/src/lib/components/index.ts @@ -3,4 +3,4 @@ import '../styles/index.css'; -export * from './Button'; +export * from './atoms'; diff --git a/apps/ui-kit/src/lib/styles/index.css b/apps/ui-kit/src/lib/styles/index.css index a35cd17f147..14e4002e1c2 100644 --- a/apps/ui-kit/src/lib/styles/index.css +++ b/apps/ui-kit/src/lib/styles/index.css @@ -46,3 +46,38 @@ font-feature-settings: 'ss01' on; } } + +@layer utilities { + .state-layer, + .state-layer-inverted { + &::after { + content: ''; + border-radius: inherit; + @apply absolute; + @apply h-full w-full; + @apply left-0 top-0; + @apply opacity-0; + @apply transition-opacity duration-75; + } + + &:hover::after { + @apply opacity-8; + } + + &:active::after { + @apply opacity-12; + } + } + + .state-layer { + &::after { + @apply bg-primary-60; + } + } + + .state-layer-inverted { + &::after { + @apply bg-primary-80; + } + } +} diff --git a/apps/ui-kit/src/storybook/stories/atoms/Button.stories.tsx b/apps/ui-kit/src/storybook/stories/atoms/Button.stories.tsx index 7b7c60a6974..39d8e118302 100644 --- a/apps/ui-kit/src/storybook/stories/atoms/Button.stories.tsx +++ b/apps/ui-kit/src/storybook/stories/atoms/Button.stories.tsx @@ -3,17 +3,14 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Button } from '@/components'; +import { Button } from '@/components/atoms/button/Button'; +import { ButtonSize, ButtonType } from '@/components/atoms/button'; const meta = { component: Button, tags: ['autodocs'], render: (props) => { - return ( -
-
- ); + return