Skip to content

Commit

Permalink
feat: remove polymorphic, use asChild
Browse files Browse the repository at this point in the history
  • Loading branch information
fran-ink committed Nov 26, 2024
1 parent 6923b87 commit 42412f8
Show file tree
Hide file tree
Showing 17 changed files with 383 additions and 259 deletions.
15 changes: 9 additions & 6 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";

import { Button, ButtonProps, InkIcon } from "../..";
import { Button, type ButtonProps } from "./index";
import { MatrixDecorator } from "../../decorators/MatrixDecorator";
import { InkIcon } from "../..";

const meta: Meta<ButtonProps<"button" | "a">> = {
const meta: Meta<ButtonProps> = {
title: "Components/Button",
decorators: [
MatrixDecorator<ButtonProps>({
Expand Down Expand Up @@ -61,10 +62,12 @@ export const WithMinimumWidth: Story = {

export const AsLink: Story = {
args: {
as: "a",
href: "/test",
target: "_blank",
children: "inkonchain.com",
asChild: true,
children: (
<a href="https://inkonchain.com" target="_blank">
inkonchain.com
</a>
),
iconRight: <InkIcon.Arrow className="ink:rotate-[225deg]" />,
},
};
76 changes: 30 additions & 46 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React, { PropsWithChildren, type ElementType } from "react";
import React, { PropsWithChildren } from "react";
import { classNames, variantClassNames } from "../../util/classes";
import { PolymorphicProps } from "../polymorphic";
import { Slot, Slottable } from "../Slot/Slot";

const DEFAULT_BUTTON_TAG = "button" as const;

export type ButtonProps<T extends ElementType = typeof DEFAULT_BUTTON_TAG> =
PolymorphicProps<T> & OwnButtonProps;

export interface OwnButtonProps extends PropsWithChildren {
export interface ButtonProps
extends PropsWithChildren,
React.ButtonHTMLAttributes<HTMLButtonElement> {
asChild?: boolean;
className?: string;
variant?: "primary" | "secondary";
size?: "sm" | "md" | "lg";
Expand All @@ -16,9 +14,8 @@ export interface OwnButtonProps extends PropsWithChildren {
iconRight?: React.ReactNode;
}

export const Button = <T extends ElementType = typeof DEFAULT_BUTTON_TAG>({
as,
asProps,
export const Button: React.FC<ButtonProps> = ({
asChild,
className,
children,
variant = "primary",
Expand All @@ -27,25 +24,24 @@ export const Button = <T extends ElementType = typeof DEFAULT_BUTTON_TAG>({
iconLeft,
iconRight,
...restProps
}: ButtonProps<T>) => {
const Component = as ?? DEFAULT_BUTTON_TAG;

}: ButtonProps) => {
const Component = asChild ? Slot : "button";
return (
<Component
className={classNames(
"ink:rounded-full ink:font-default ink:transition-colors ink:hover:cursor-pointer ink:disabled:cursor-not-allowed ink:duration-100",
"ink:rounded-full ink:font-default ink:transition-colors ink:hover:cursor-pointer ink:disabled:cursor-not-allowed ink:duration-100 ink:box-border",
"ink:flex ink:items-center ink:justify-center ink:gap-1 ink:select-none ink:no-underline",
variantClassNames(size, {
sm: "ink:px-2 ink:py-1.5 ink:text-body-2-bold",
md: "ink:px-3 ink:py-2 ink:text-body-2-bold",
lg: "ink:px-4 ink:py-3 ink:text-h4",
sm: "ink:px-2 ink:py-1.5 ink:text-body-2-bold ink:h-5",
md: "ink:px-3 ink:py-2 ink:text-body-2-bold ink:h-6",
lg: "ink:px-4 ink:py-3 ink:text-h4 ink:h-8",
}),
variantClassNames(rounded, {
full: variantClassNames(size, {
sm: "ink:rounded-full ink:p-1",
md: "ink:rounded-full ink:p-1.5",
lg: "ink:rounded-full ink:p-2",
}),
full: `ink:rounded-full ${variantClassNames(size, {
sm: "ink:p-1 ink:size-5",
md: "ink:p-1.5 ink:size-6",
lg: "ink:p-2 ink:size-8",
})}`,
default: "",
}),
variantClassNames(variant, {
Expand All @@ -56,31 +52,19 @@ export const Button = <T extends ElementType = typeof DEFAULT_BUTTON_TAG>({
}),
className
)}
{...asProps}
{...restProps}
>
{iconLeft && <div className="ink:size-3 ink:-my-1">{iconLeft}</div>}
{rounded === "full" ? (
<div
className={variantClassNames(size, {
sm: "ink:size-3",
md: "ink:size-3",
lg: "ink:size-3 ink:m-0.5",
})}
>
{children}
</div>
) : (
<div
className={classNames(
"ink:flex ink:items-center ink:justify-center ink:gap-1.5 ink:h-2",
!iconLeft && !iconRight && "ink:w-full"
)}
>
{children}
</div>
)}
{iconRight && <div className="ink:size-3 ink:-my-1">{iconRight}</div>}
<Slottable child={children}>
{(child) => (
<>
{iconLeft && <div className="ink:size-3 ink:-my-1">{iconLeft}</div>}
{child}
{iconRight && (
<div className="ink:size-3 ink:-my-1">{iconRight}</div>
)}
</>
)}
</Slottable>
</Component>
);
};
81 changes: 41 additions & 40 deletions src/components/Button/InternalButton.tsx
Original file line number Diff line number Diff line change
@@ -1,81 +1,82 @@
import { ElementType } from "react";
import { classNames, variantClassNames } from "../../util/classes";
import { Slot, Slottable } from "../Slot";
import { ButtonProps } from "./Button";

import { Button } from "./Button";

const DEFAULT_BUTTON_TAG = "button" as const;

export type InternalButtonProps<
T extends ElementType = typeof DEFAULT_BUTTON_TAG,
> = Omit<ButtonProps<T>, "variant" | "size"> & InternalButtonOwnProps;
export type InternalButtonProps = Omit<ButtonProps, "variant" | "size"> &
InternalButtonOwnProps;

export type InternalButtonVariant = "wallet" | "wallet-inside";

export interface InternalButtonOwnProps {
variant: InternalButtonVariant | ButtonProps["variant"];
}

export const InternalButton = <
T extends ElementType = typeof DEFAULT_BUTTON_TAG,
>({
export const InternalButton: React.FC<InternalButtonProps> = ({
children,
className,
variant,
iconLeft,
asChild,
...props
}: InternalButtonProps<T>) => {
}) => {
const Component = asChild ? Slot : Button;
return (
<Button
<Component
className={classNames(
variantClassNames(variant as InternalButtonVariant, {
wallet:
"ink:bg-background-light-transparent ink:pl-1 ink:pr-1.5 ink:py-2 ink:text-body-2-bold ink:text-text-default ink:hover:bg-background-light ink:disabled:bg-background-light-transparent-disabled ink:disabled:text-muted ink:active:bg-background-light",
"wallet-inside":
"ink:bg-background-light-invisible ink:px-1.5 ink:rounded-xs ink:text-body-2-bold ink:text-text-default ink:hover:bg-background-container ink:disabled:bg-background-light-transparent-disabled ink:disabled:text-muted ink:active:bg-background-light",
"ink:bg-background-light-invisible ink:px-1.5 ink:py-2 ink:rounded-xs ink:text-body-2-bold ink:text-text-default ink:hover:bg-background-container ink:disabled:bg-background-light-transparent-disabled ink:disabled:text-muted ink:active:bg-background-light",
}),
className
)}
size="md"
variant={
variant === "primary" || variant === "secondary" ? variant : undefined
}
{...(props as ButtonProps<T>)}
{...props}
>
<div
className={classNames(
"ink:w-full ink:flex-1 ink:flex ink:items-center ink:gap-1.5",
variantClassNames(variant as InternalButtonVariant, {
wallet: "ink:justify-center",
"wallet-inside": "ink:justify-start",
})
)}
>
{iconLeft && (
<Slottable child={children}>
{(child) => (
<div
className={classNames(
"ink:flex ink:items-center ink:justify-center",
"ink:w-full ink:flex-1 ink:flex ink:items-center ink:gap-1.5",
variantClassNames(variant as InternalButtonVariant, {
wallet: "ink:size-4",
"wallet-inside": "ink:size-3",
wallet: "ink:justify-center",
"wallet-inside": "ink:justify-start",
})
)}
>
<div
className={classNames(
"ink:flex ink:items-center ink:justify-center ink:rounded-full ink:overflow-hidden",
variantClassNames(variant as InternalButtonVariant, {
wallet: "ink:size-4",
"wallet-inside": "ink:size-3",
})
)}
>
{iconLeft}
</div>
{iconLeft && (
<div
className={classNames(
"ink:flex ink:items-center ink:justify-center",
variantClassNames(variant as InternalButtonVariant, {
wallet: "ink:size-4",
"wallet-inside": "ink:size-3",
})
)}
>
<div
className={classNames(
"ink:flex ink:items-center ink:justify-center ink:rounded-full ink:overflow-hidden",
variantClassNames(variant as InternalButtonVariant, {
wallet: "ink:size-4",
"wallet-inside": "ink:size-3",
})
)}
>
{iconLeft}
</div>
</div>
)}
{child}
</div>
)}
<div>{children}</div>
</div>
</Button>
</Slottable>
</Component>
);
};
2 changes: 1 addition & 1 deletion src/components/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Input, InputProps } from "./Input";
import { Input, type InputProps } from "./index";

const meta: Meta<InputProps> = {
title: "Components/Input",
Expand Down
9 changes: 6 additions & 3 deletions src/components/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { Meta, StoryObj } from "@storybook/react";

import { Modal, ModalProps } from "./Modal";
import { Button } from "../Button";
import { ModalProvider } from "./ModalContext";
import { useModalContext } from "./ModalContext";
import {
ModalProvider,
useModalContext,
Modal,
type ModalProps,
} from "./index";
import { fn } from "@storybook/test";
import { ModalLayout } from ".";

Expand Down
54 changes: 24 additions & 30 deletions src/components/SegmentedControl/SegmentedControl.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import { SegmentedControl, SegmentedControlProps } from "./SegmentedControl";
import { SegmentedControl, SegmentedControlProps } from "./index";

const meta: Meta<SegmentedControlProps<string, "button" | "a">> = {
const meta: Meta<SegmentedControlProps<string>> = {
title: "Components/SegmentedControl",
component: SegmentedControl,
tags: ["autodocs"],
args: {
onOptionChange: fn(),
options: [
{
label: "First",
children: "First",
value: "first",
selectedByDefault: true,
},
{
label: "Second",
children: "Second",
value: "second",
},
{
label: "Third",
children: "Third",
value: "third",
},
],
Expand All @@ -38,7 +38,7 @@ export const VariableTabWidth: Story = {
variableTabWidth: true,
options: Array.from(new Array(5)).map((_, i) => ({
selectedByDefault: i === 0,
label: (i + 1).toString().repeat(i + 1),
children: (i + 1).toString().repeat(i + 1),
value: (i + 1).toString(),
})),
},
Expand All @@ -52,38 +52,32 @@ export const AsLinks: Story = {
args: {
options: [
{
label: "First",
children: (
<a href="#first" target="_self">
First
</a>
),
value: "first",
selectedByDefault: true,
props: {
as: "a",
asProps: {
href: "#first",
target: "_self",
},
},
asChild: true,
},
{
label: "Second",
children: (
<a href="#second" target="_self">
Second
</a>
),
value: "second",
props: {
as: "a",
asProps: {
href: "#second",
target: "_self",
},
},
asChild: true,
},
{
label: "Third",
children: (
<a href="#third" target="_self">
Third
</a>
),
value: "third",
props: {
as: "a",
asProps: {
href: "#third",
target: "_self",
},
},
asChild: true,
},
],
},
Expand Down
Loading

0 comments on commit 42412f8

Please sign in to comment.