Skip to content

Commit

Permalink
add: radio group draft
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherkindl committed Nov 2, 2023
1 parent 6ca2f4b commit 20a4e45
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/components/input-elements/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";
import { RadioGroup as HeadlessRadioGroup } from "@headlessui/react";
import { makeClassName, tremorTwMerge } from "lib";
import React from "react";

const makeRadioGroupClassName = makeClassName("RadioGroup");

export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
defaultValue?: string[];
value?: string[];
onChange?: (value: any) => void; // @SEV: does this need to be declared here? see e.g. BaseInput
disabled?: boolean;
name?: string;
id?: string;
}

const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>((props, ref) => {
const { defaultValue, value, onChange, children, disabled, name, id, className, ...other } =
props;

return (
<HeadlessRadioGroup
as="div"
ref={ref}
defaultValue={defaultValue}
value={value}
onChange={onChange}
disabled={disabled}
name={name}
id={id}
className={tremorTwMerge(makeRadioGroupClassName("root"), className)}
{...other}
>
{children}
</HeadlessRadioGroup>
);
});

RadioGroup.displayName = "RadioGroup";

export default RadioGroup;
32 changes: 32 additions & 0 deletions src/components/input-elements/RadioGroup/RadioGroupOption.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";
import { RadioGroup as HeadlessRadioGroup } from "@headlessui/react";
import { makeClassName, tremorTwMerge } from "lib";
import React from "react";

const makeRadioGroupOptionClassName = makeClassName("RadioGroup");

export interface RadioGroupOptionProps extends React.HTMLAttributes<HTMLDivElement> {
value?: string[];
disabled?: boolean;
}

const RadioGroupOption = React.forwardRef<HTMLDivElement, RadioGroupOptionProps>((props, ref) => {
const { value, children, disabled, className, ...other } = props;

return (
<HeadlessRadioGroup.Option
as="div"
ref={ref}
value={value}
disabled={disabled}
className={tremorTwMerge(makeRadioGroupOptionClassName("root"), className)}
{...other}
>
{children}
</HeadlessRadioGroup.Option>
);
});

RadioGroupOption.displayName = "RadioGroupOption";

export default RadioGroupOption;
4 changes: 4 additions & 0 deletions src/components/input-elements/RadioGroup/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as RadioGroup } from "./RadioGroup";
export type { RadioGroupProps } from "./RadioGroup";
export { default as RadioGroupOption } from "./RadioGroupOption";
export type { RadioGroupOptionProps } from "./RadioGroupOption";
1 change: 1 addition & 0 deletions src/components/input-elements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./Select";
export * from "./Tabs";
export * from "./TextInput";
export * from "./Switch";
export * from "./RadioGroup";
145 changes: 145 additions & 0 deletions src/stories/input-elements/RadioGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import type { Meta, StoryObj } from "@storybook/react";
// import { RadioGroup, RadioGroupOption } from "components";
import { RadioGroup } from "@headlessui/react";
import { CheckCircleIcon } from "@heroicons/react/solid";
import React, { useState } from "react";

const platformPrices = [
{ id: 0, title: "Starter", description: "Up to 300 requests per day" },
{
id: 2,
title: "Premium",
description: "Unlimited requests per month",
},
{ id: 3, title: "Enterprise", description: "Based on your specific needs" },
];

interface StringJoiner {
(...classes: string[]): string;
}
const classNames: StringJoiner = (...classes: string[]): string =>
classes.filter(Boolean).join(" ");

const meta: Meta<typeof RadioGroup> = {
title: "Components/Input/RadioGroup",
component: RadioGroup,
};

export default meta;
type Story = StoryObj<typeof RadioGroup>;

function CardTemplate() {
const [selectedPlatform, setSelectedPlatform] = useState(platformPrices[0]);
return (
<div className="p-10">
{/* <RadioGroup value={selectedPlatform} onChange={setSelectedPlatform} name="platform">
<div className="mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-3 sm:gap-x-4">
{platformPrices.map((priceTier) => (
<RadioGroupOption
key={priceTier.id}
value={priceTier.id}
className={({ active }) =>
classNames(
active
? "border border-blue-400 ring-2 ring-blue-200 transition-all"
: "ring-1 ring-gray-200 border-transparent",
"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm transition-all",
)
}
>
{({ checked, active }) => (
<>
<span className="flex flex-1">
<span className="flex flex-col">
<span className="block text-sm font-medium text-slate-900">
{priceTier.title}
</span>
<span className="mt-1 flex items-center text-sm text-slate-500">
{priceTier.description}
</span>
</span>
</span>
<CheckCircleIcon
className={classNames(!checked ? "invisible" : "", "h-5 w-5 text-blue-500")}
aria-hidden="true"
/>
<span
className={classNames(
active ? "border" : "",
checked
? "border border-blue-400 ring-2 ring-blue-200"
: "border-transparent",
"pointer-events-none absolute -inset-px rounded-lg",
)}
aria-hidden="true"
/>
</>
)}
</RadioGroupOption>
))}
</div>
</RadioGroup> */}
<RadioGroup value={selectedPlatform} onChange={setSelectedPlatform} name="platform">
<div className="mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-3 sm:gap-x-4">
{platformPrices.map((priceTier) => (
<RadioGroup.Option
key={priceTier.id}
value={priceTier}
className={({ active }) =>
classNames(
active
? "border border-blue-400 ring-2 ring-blue-200 transition-all"
: "ring-1 ring-gray-200 border-transparent ",
"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm transition-all",
)
}
>
{({ checked, active }) => (
<>
<span className="flex flex-1">
<span className="flex flex-col">
<RadioGroup.Label
as="span"
className="block text-sm font-medium text-slate-900"
>
{priceTier.title}
</RadioGroup.Label>
<RadioGroup.Description
as="span"
className="mt-1 flex items-center text-sm text-slate-500"
>
{priceTier.description}
</RadioGroup.Description>
</span>
</span>
<CheckCircleIcon
className={classNames(!checked ? "invisible" : "", "h-5 w-5 text-blue-500")}
aria-hidden="true"
/>
<span
className={classNames(
active ? "border" : "",
checked
? "border border-blue-400 ring-2 ring-blue-200"
: "border-transparent",
"pointer-events-none absolute -inset-px rounded-lg",
)}
aria-hidden="true"
/>
</>
)}
</RadioGroup.Option>
))}
</div>
</RadioGroup>
</div>
);
}

const Cards: Story = {
render: CardTemplate,
};

export const CardsCustomStyled: Story = {
...Cards,
};

0 comments on commit 20a4e45

Please sign in to comment.