diff --git a/apps/design-system/stories/iconButton.stories.tsx b/apps/design-system/stories/iconButton.stories.tsx new file mode 100644 index 0000000..79548f8 --- /dev/null +++ b/apps/design-system/stories/iconButton.stories.tsx @@ -0,0 +1,28 @@ +import { IconButton } from "@repo/design-system/iconButton"; +import { StarIcon } from "@repo/design-system/starIcon"; +import { Meta, StoryObj } from "@storybook/react"; + +export default { + title: "Components/IconButton", + component: IconButton, + argTypes: { + size: { + control: { type: "select", options: ["small", "default", "large"] }, + }, + iconSize: { + control: { type: "select", options: ["small", "default", "large"] }, + }, + }, + tags: ["autodocs"], +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + size: "default", + iconSize: "default", + icon: StarIcon, + children: "Icon button", + }, +}; diff --git a/apps/design-system/stories/starIconButton.stories.tsx b/apps/design-system/stories/starIconButton.stories.tsx new file mode 100644 index 0000000..b35fcd8 --- /dev/null +++ b/apps/design-system/stories/starIconButton.stories.tsx @@ -0,0 +1,16 @@ +import { StarIconButton } from "@repo/design-system/starIconButton"; +import { Meta, StoryObj } from "@storybook/react"; + +export default { + title: "Components/StarIconButton", + component: StarIconButton, + tags: ["autodocs"], +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + pressed: true + } +}; diff --git a/apps/design-system/stories/toggleButton.stories.tsx b/apps/design-system/stories/toggleButton.stories.tsx new file mode 100644 index 0000000..6f26bdf --- /dev/null +++ b/apps/design-system/stories/toggleButton.stories.tsx @@ -0,0 +1,66 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { ToggleButton } from "@repo/design-system/toggleButton"; +import { YesIcon } from "@repo/design-system/yesIcon"; +import { Button } from "@repo/design-system/button"; + +export default { + title: "Components/ToggleButton", + component: ToggleButton, + argTypes: {}, + tags: ["autodocs"], +} as Meta; + +type Story = StoryObj; + +export const AnswerInFavour: Story = { + render: () => ( + + + + ), +}; + +export const AnswerAgainst: Story = { + args: { + answerType: "Against", + children: "Jsem proti", + hasIcon: true, + icon: YesIcon, + iconPosition: "left", + color: "secondary", + kind: "inverse", + size: "default", + wider: true, + fitContent: true, + compactable: true, + }, +}; + +export const AnswerNeutral: Story = { + args: { + answerType: "Neutral", + children: "Přeskočit", + hasIcon: true, + icon: YesIcon, + iconPosition: "left", + color: "neutral", + kind: "inverse", + size: "default", + wider: true, + fitContent: true, + compactable: true, + }, +}; diff --git a/apps/design-system/stories/toggleIconButton.stories.tsx b/apps/design-system/stories/toggleIconButton.stories.tsx new file mode 100644 index 0000000..1c327f1 --- /dev/null +++ b/apps/design-system/stories/toggleIconButton.stories.tsx @@ -0,0 +1,19 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { ToggleIconButton } from "@repo/design-system/toggleIconButton"; + +export default { + title: "Components/ToggleIconButton", + component: ToggleIconButton, + argTypes: {}, + tags: ["autodocs"], +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + iconDefault: () => , + iconPressed: () => , + children: "Click me", + }, +}; diff --git a/packages/design-system/package.json b/packages/design-system/package.json index cb0ce5f..5c36360 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -11,11 +11,17 @@ "./tailwind": "./tailwind.config.ts", "./demo": "./src/index.ts", "./progressBar": "./src/progressBar.tsx", - "./arrowIcon": "./src/arrowIcon.tsx", + "./iconButton": "./src/iconButton.tsx", + "./starIconButton": "./src/starIconButton.tsx", "./starIcon": "./src/starIcon.tsx", + "./starIconFilled": "./src/starIconFilled.tsx", + "./toggleIconButton": "./src/toggleIconButton.tsx", + "./toggleButton": "./src/toggleButton.tsx", "./yesIcon": "./src/yesIcon.tsx", - "./noIcon": "./src/noIcon.tsx", - "./neutralIcon": "./src/neutralIcon.tsx" + "./button": "./src/button.tsx", + "./buttonInFavour": "./src/buttonInFavour.tsx", + "./buttonAgainst": "./src/buttonAgainst.tsx", + "./buttonNeutral": "./src/buttonNeutral.tsx" }, "scripts": { "build": "npm run fonts && npm run tailwind", diff --git a/packages/design-system/src/button.tsx b/packages/design-system/src/button.tsx new file mode 100644 index 0000000..c3dfb6b --- /dev/null +++ b/packages/design-system/src/button.tsx @@ -0,0 +1,160 @@ +import React from "react"; +import { Button as HeadlessUIButton } from "@headlessui/react"; +import { cva, VariantProps } from "class-variance-authority"; + +const buttonVariants = cva( + [ + "k1-inline-flex k1-items-center k1-min-w-fit", + "data-[hover]:k1-cursor-pointer k1-text-nowrap data-[disabled]:k1-pointer-events-none", + "k1-uppercase k1-font-bold", + "k1-rounded-l-[16px] k1-rounded-br-[16px]", + "k1-select-none", + "k1-gap-2", + ], + { + variants: { + kind: { + filled: + "k1-p-4 data-[active]:k1-bg-primary-strong-active data-[disabled]:k1-bg-neutral-disaled", + inverse: "k1-border-2 k1-bg-transparent k1-p-4 k1-gap-4", + outline: "k1-border-2 k1-bg-transparent k1-p-4", + link: [ + "k1-bg-transparent k1-text-neutral k1-p-0 k1-gap-2", + "k1-border-0", + "data-[hover]:k1-text-neutral-hover", + "data-[active]:k1-text-neutral-active", + "data-[disabled]:k1-text-neutral-disabled", + ], + }, + hasIcon: { + true: "k1-justify-between", + false: "k1-justify-center", + }, + iconPosition: { + left: "k1-flex-row", + right: "k1-flex-row-reverse", + }, + color: { + primary: [ + "k1-bg-primary-strong", + "data-[hover]:k1-bg-primary-strong-hover data-[hover]-k1-text-white", + ], + secondary: [ + "k1-bg-secondary-strong", + "data-[hover]:k1-bg-secondary-strong-hover", + "data-[disabled]:k1-bg-neutral-disaled", + ], + neutral: [ + "k1-border-2 k1-text-neutral k1-border-neutral-strong", + "data-[hover]:k1-bg-neutral-backdrop-hover data-[hover]:k1-border-neutral-strong", + "data-[active]:k1-bg-neutral-backdrop-active data-[active]:k1-text-neutral-active", + "data-[disabled]:k1-border-neutral-disabled data-[disabled]:k1-text-neutral-disabled", + ], + }, + size: { + default: "k1-h-14 k1-text-sm k1-tracking-wider k1-leading-6", + small: "k1-h-10 k1-text-xs k1-tracking-wider k1-leading-4", + }, + wider: { + true: "k1-px-6", + }, + fitContent: { + true: "k1-w-fit", + false: "k1-w-full", + }, + }, + + defaultVariants: { + kind: "filled", + size: "default", + fitContent: false, + }, + + compoundVariants: [ + { + kind: "inverse", + color: "primary", + className: [ + "k1-border-primary-strong k1-text-primary", + "data-[hover]:k1-border-primary-strong-hover data-[hover]:k1-text-neutral-inverse data-[hover]:k1-bg-primary-strong-hover", + "data-[active]:k1-bg-primary-strong data-[active]:k1-text-neutral-inverse data-[active]:k1-border-primary-strong-active", + "data-[pressed]:k1-bg-primary-strong data-[pressed]:k1-text-neutral-inverse", + ], + }, + { + kind: "inverse", + color: "secondary", + className: [ + "k1-border-secondary-strong k1-text-secondary", + "data-[hover]:k1-border-secondary-strong-hover data-[hover]:k1-text-neutral-inverse data-[hover]:k1-bg-secondary-strong-hover", + "data-[active]:k1-bg-secondary-strong data-[active]:k1-text-neutral-inverse data-[active]:k1-border-secondary-strong-active", + "data-[pressed]:k1-bg-secondary-strong data-[pressed]:k1-text-neutral-inverse", + ], + }, + { + kind: "inverse", + color: "neutral", + className: [ + "k1-border-neutral-strong k1-text-neutral k1-gap-4", + "data-[hover]:k1-border-neutral-strong-hover data-[hover]:k1-text-neutral-inverse data-[hover]:k1-bg-neutral-strong-hover", + "data-[active]:k1-bg-neutral-strong-active data-[active]:k1-text-neutral-inverse data-[active]:k1-border-neutral-active", + "data-[pressed]:k1-bg-neutral-strong-active data-[pressed]:k1-text-neutral-inverse", + ], + }, + ], + }, +); + +type Props = React.ButtonHTMLAttributes & + VariantProps & { + pressed?: boolean; + answerType?: string; + children: React.ReactNode; + compactable?: boolean; + icon?: React.ComponentType>; + }; + +const Button = React.forwardRef( + ( + { + children, + kind, + color, + iconPosition, + size, + wider, + fitContent, + compactable, + pressed, + answerType, + ...props + }, + ref, + ) => { + const Icon = props.icon; + const hasIcon = !!Icon; + + return ( + + {hasIcon ? : null} +
+ {children} +
+
+ ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/packages/design-system/src/iconButton.tsx b/packages/design-system/src/iconButton.tsx new file mode 100644 index 0000000..63e5273 --- /dev/null +++ b/packages/design-system/src/iconButton.tsx @@ -0,0 +1,66 @@ +import React from "react"; +import { Button, ButtonProps } from "@headlessui/react"; +import { cva, VariantProps } from "class-variance-authority"; + +const IconButtonVariants = cva( + ["k1-inline-flex k1-gap-2 k1-items-center k1-w-auto k1-select-none"], + + { + variants: { + size: { + small: "k1-w-8 k1-h-8", + default: "k1-w-10 k1-h-10", + large: "k1-w-14 k1-h-14", + }, + }, + }, +); + +const IconVariants = cva( + [ + "k1-flex k1-justify-center k1-items-center k1-rounded-full hover:k1-bg-neutral-backdrop-hover active:k1-bg-neutral-backdrop-active", + ], + { + variants: { + iconWrapper: { + small: "k1-h-8 k1-w-8", + default: "k1-h-10 k1-w-10", + large: "k1-h-14 k1-w-14", + }, + iconSize: { + small: "k1-h-4 k1-w-4", + default: "k1-h-6 k1-w-6", + large: "k1-h-10 k1-w-10", + }, + }, + }, +); + +type Props = { + pressed?: boolean; + children?: React.ReactNode; + icon: React.ComponentType>; + "aria-label"?: string; +} & VariantProps & + VariantProps & + ButtonProps; + +const IconButton = React.forwardRef( + ({ icon: Icon, size, iconWrapper, iconSize, children, ...props }, ref) => { + return ( + + ); + }, +); + +export { IconButton, IconButtonVariants, IconVariants }; + +//TODO: +// 1. fix wrapper/icon hover bug +// 2. iconWrapper hover on button hover diff --git a/packages/design-system/src/starIcon.tsx b/packages/design-system/src/starIcon.tsx new file mode 100644 index 0000000..4cacc7b --- /dev/null +++ b/packages/design-system/src/starIcon.tsx @@ -0,0 +1,18 @@ +export function StarIcon( + props: React.JSX.IntrinsicAttributes & React.SVGProps, +) { + return ( + + {props.children} + + + ); +} diff --git a/packages/design-system/src/starIconButton.tsx b/packages/design-system/src/starIconButton.tsx new file mode 100644 index 0000000..d68291b --- /dev/null +++ b/packages/design-system/src/starIconButton.tsx @@ -0,0 +1,23 @@ +import React, { ComponentProps } from "react"; +import { ToggleIconButton } from "@repo/design-system/toggleIconButton"; +import { StarIcon } from "@repo/design-system/starIcon"; +import { StarIconFilled } from "@repo/design-system/starIconFilled"; + +type Props = Omit< + ComponentProps, + "iconDefault" | "iconPressed" +>; + +const StarIconButton = (props: Props) => { + return ( + + Pro mě důležité + + ); +}; + +export { StarIconButton }; diff --git a/packages/design-system/src/starIconFilled.tsx b/packages/design-system/src/starIconFilled.tsx new file mode 100644 index 0000000..9775683 --- /dev/null +++ b/packages/design-system/src/starIconFilled.tsx @@ -0,0 +1,18 @@ +export function StarIconFilled( + props: React.JSX.IntrinsicAttributes & React.SVGProps, +) { + return ( + + {props.children} + + + ); +} diff --git a/packages/design-system/src/toggleButton.tsx b/packages/design-system/src/toggleButton.tsx new file mode 100644 index 0000000..3620667 --- /dev/null +++ b/packages/design-system/src/toggleButton.tsx @@ -0,0 +1,64 @@ +// import React, { useState, ComponentProps } from "react"; +// import { Button, buttonVariants } from "@repo/design-system/button"; +// import { VariantProps } from "class-variance-authority"; + +// type Props = VariantProps & +// ComponentProps & { +// children: React.ReactElement; +// }; + +// const ToggleButton = React.forwardRef, Props>( +// ({ children, ...props }, ref) => { +// const [isPressed, setIsPressed] = useState(false); + +// function handlePressed() { +// setIsPressed((prevState) => !prevState); +// } + +// Child check +// if (React.isValidElement(children)) { +// return React.cloneElement(children, { +// onClick: handlePressed, +// pressed: isPressed, +// ref, +// ...props, +// }); +// } + +// Fallback +// return ( +// +// ); +// }, +// ); + +// export { ToggleButton }; + +// original solution + +import React, { useState, ComponentProps } from "react"; +import { Button, buttonVariants } from "@repo/design-system/button"; +import { VariantProps } from "class-variance-authority"; + +type Props = VariantProps & + Omit, "onClick">; +const ToggleButton = React.forwardRef, Props>( + ({ ...props }, ref) => { + const [isPressed, setIsPressed] = useState(false); + function handlePressed() { + setIsPressed((prevState) => !prevState); + } + return ( +