Skip to content

Commit

Permalink
[sparkle] - refacto: Checkbox / RadioGroup (#8752)
Browse files Browse the repository at this point in the history
* [sparkle/src/components] - refactor: centralize Checkbox size styles

- Extract size variant mapping from the Checkbox component into a separate constant for better maintainability
- Replace inlined size variant definitions in the component with the new centralized `checkboxSizeVariant` mapping

[sparkle/src/stories] - feature: update Checkbox stories with enhanced controls and structure

- Introduce controls for size, checked state, and disabled state with descriptions and default values in the Checkbox story
- Add `text` and `description` properties with conditional rendering logic for more comprehensive story examples
- Implement action handlers for onChange events in Checkbox stories to better demonstrate component interaction

* [sparkle] - feature: integrate labels directly into RadioGroupItems

 - Implemented direct label support within the RadioGroupItem component for better encapsulation
 - Updated RadioGroupItem usage in stories to leverage the new label prop, simplifying layout
 - Enhanced RadioGroupItem styling to accommodate label inclusion
 - Adjusted RadioGroupChoice to a flex-column layout to align with new item structure

* [sparkle] - refactor: improve readability and syntax conformity in RadioGroup components

 - Reorder imports to maintain consistent structure across files
 - Add missing semicolons for code consistency
 - Reformat props spreading for better readability
 - Simplify JSX structure by removing redundant divs and merging classNames
 - Adjust stories for RadioGroup to provide clearer examples with proper htmlFor attributes

* [sparkle] - refactor: simplify label prop usage in RadioGroup components

 - Refactor RadioGroup stories to use string labels directly instead of wrapping them with a Label component

* [sparkle] - refactor: update `RadioGroup` to support ReactNode labels

 - Removed `Label` component import, allowing more flexible `label` prop types in `RadioGroupItem`
 - Replaced static text labels with JSX labels in `RadioGroup.stories`
 - Simplified the wrapper div class logic for RadioGroupItem components
 - Enhanced `RadioGroupWithChildrenExample` with additional icon and style adjustments

* [sparkle] - fix: ensure RadioGroup items use full width

 - Added a class to make RadioGroup items use the full available width for better layout control

* [sparkle] - feature: bump package version to 0.2.322

 - Increment package version for a new release with latest changes and fixes
  • Loading branch information
JulesBelveze authored Nov 22, 2024
1 parent 591886a commit 45af7db
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 83 deletions.
4 changes: 2 additions & 2 deletions sparkle/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sparkle/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dust-tt/sparkle",
"version": "0.2.321",
"version": "0.2.322",
"scripts": {
"build": "rm -rf dist && npm run tailwind && npm run build:esm && npm run build:cjs",
"tailwind": "tailwindcss -i ./src/styles/tailwind.css -o dist/sparkle.css",
Expand Down
13 changes: 9 additions & 4 deletions sparkle/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { cn } from "@sparkle/lib/utils";
import { Icon } from "./Icon";
import { Label } from "./Label";

export const CHECKBOX_SIZES = ["xs", "sm"] as const;
type CheckboxSizeType = (typeof CHECKBOX_SIZES)[number];

const checkboxSizeVariant: Record<CheckboxSizeType, string> = {
xs: "s-h-4 s-w-4 s-rounded",
sm: "s-h-5 s-w-5 s-rounded-md",
};

const checkboxStyles = cva(
cn(
"s-shrink-0 s-peer s-border s-text-foreground s-border-border-darker",
Expand All @@ -22,10 +30,7 @@ const checkboxStyles = cva(
partial: "data-[state=checked]:s-bg-muted-foreground",
false: "",
},
size: {
xs: "s-h-4 s-w-4 s-rounded",
sm: "s-h-5 s-w-5 s-rounded-md",
},
size: checkboxSizeVariant,
},
defaultVariants: {
size: "sm",
Expand Down
25 changes: 18 additions & 7 deletions sparkle/src/components/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,22 @@ interface RadioGroupItemProps
VariantProps<typeof radioStyles> {
tooltipMessage?: string;
tooltipAsChild?: boolean;
label?: React.ReactNode;
}

const RadioGroupItem = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
RadioGroupItemProps
>(
(
{ tooltipMessage, className, size, tooltipAsChild = false, ...props },
{
tooltipMessage,
className,
size,
tooltipAsChild = false,
label,
...props
},
ref
) => {
const item = (
Expand All @@ -81,10 +89,9 @@ const RadioGroupItem = React.forwardRef<
/>
</RadioGroupPrimitive.Item>
);
return (
<div
className={cn("s-group", size === "sm" ? "s-h-5 s-w-5" : "s-h-4 s-w-4")}
>

const wrappedItem = (
<div className="s-flex s-items-center s-gap-2">
{tooltipMessage ? (
<Tooltip
triggerAsChild={tooltipAsChild}
Expand All @@ -94,11 +101,13 @@ const RadioGroupItem = React.forwardRef<
) : (
item
)}
{label}
</div>
);

return <div className="s-w-full s-group">{wrappedItem}</div>;
}
);
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;

type IconPosition = "start" | "center" | "end";

Expand All @@ -111,7 +120,9 @@ const RadioGroupChoice = React.forwardRef<
RadioGroupChoiceProps
>(({ className, size, iconPosition = "center", children, ...props }, ref) => {
return (
<div className={cn("s-flex", className, `s-items-${iconPosition}`)}>
<div
className={cn("s-flex s-flex-col", className, `s-items-${iconPosition}`)}
>
<RadioGroupItem
ref={ref}
className={cn(radioStyles({ size }))}
Expand Down
144 changes: 87 additions & 57 deletions sparkle/src/stories/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,102 @@
import type { Meta } from "@storybook/react";
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";

import { CHECKBOX_SIZES } from "@sparkle/components/Checkbox";

import {
Checkbox,
type CheckboxProps,
CheckboxWithText,
CheckBoxWithTextAndDescription,
} from "../index_with_tw_base";

const CHECKED_STATES = {
unchecked: false,
checked: true,
partial: "partial",
} as const;

type ExtendedCheckboxProps = CheckboxProps & {
text?: string;
description?: string;
};

const meta = {
title: "Primitives/Checkbox",
component: Checkbox,
} satisfies Meta<typeof Checkbox>;
// We need to cast here as the component expects stricter props
component: Checkbox as React.ComponentType<ExtendedCheckboxProps>,
parameters: {
layout: "centered",
},
argTypes: {
size: {
description: "The size of the checkbox",
options: CHECKBOX_SIZES,
control: { type: "select" },
table: {
defaultValue: { summary: "sm" },
},
},
checked: {
description: "The checked state of the checkbox",
options: Object.keys(CHECKED_STATES),
mapping: CHECKED_STATES,
control: { type: "select" },
table: {
type: { summary: "boolean | 'partial'" },
defaultValue: { summary: "false" },
},
},
disabled: {
description: "Whether the checkbox is disabled",
control: "boolean",
table: {
defaultValue: { summary: false },
},
},
className: {
description: "Additional CSS classes to apply",
control: "text",
},
text: {
description: "Optional text label to display next to the checkbox",
control: "text",
},
description: {
description:
"Optional description text (only shown when text is provided)",
control: "text",
if: { arg: "text" },
},
onChange: {
description: "Callback when checkbox state changes",
action: "changed",
},
},
} satisfies Meta<ExtendedCheckboxProps>;

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

const handleChange = () => {
// This function intentionally left blank
};

export const CheckBoxSizesExample = () => {
return (
<div className="s-flex s-flex-col s-gap-10">
<div className="s-flex s-gap-10">
SM
<Checkbox onChange={handleChange} />
<Checkbox disabled onChange={handleChange} />
<Checkbox checked onChange={handleChange} />
<Checkbox checked disabled onChange={handleChange} />
<Checkbox checked="partial" onChange={handleChange} />
<Checkbox checked="partial" disabled onChange={handleChange} />
</div>
<div className="s-flex s-gap-10">
XS
<Checkbox size="xs" onChange={handleChange} />
<Checkbox size="xs" disabled onChange={handleChange} />
<Checkbox size="xs" checked onChange={handleChange} />
<Checkbox size="xs" checked disabled onChange={handleChange} />
<Checkbox size="xs" checked="partial" onChange={handleChange} />
<Checkbox
size="xs"
checked="partial"
disabled
onChange={handleChange}
export const Default: Story = {
args: {
size: "sm",
checked: false,
disabled: false,
},
render: ({ text, description, ...args }) => {
if (text && description) {
return (
<CheckBoxWithTextAndDescription
text={text}
description={description}
{...args}
/>
</div>
</div>
);
};

export const CheckBoxWithTextExample = () => {
return (
<div className="s-flex s-gap-10">
<CheckboxWithText text="Google Drive" />
</div>
);
};

export const CheckBoxWithTextAndDescriptionExample = () => {
return (
<div className="s-flex s-flex-col s-gap-3">
<CheckBoxWithTextAndDescription
text="Google Drive"
description="This is a nice Google Drive description."
/>
<CheckBoxWithTextAndDescription
text="Microsoft"
description="This is a nice Microsoft description."
/>
</div>
);
);
}
if (text) {
return <CheckboxWithText text={text} {...args} />;
}
return <Checkbox {...args} />;
},
};
47 changes: 35 additions & 12 deletions sparkle/src/stories/RadioGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from "react";

import {
Button,
FolderIcon,
Icon,
Label,
LockIcon,
Expand All @@ -21,16 +22,25 @@ export const RadioGroupExample = () => {
<div className="s-flex s-flex-col s-gap-10">
<RadioGroup defaultValue="option-one">
<div className="s-flex s-items-center s-space-x-2">
<RadioGroupItem value="option-one" id="option-one" />
<Label htmlFor="option-one">Option One</Label>
<RadioGroupItem
value="option-one"
id="option-one"
label={<Label htmlFor="option-one">Option One</Label>}
/>
</div>
<div className="s-flex s-items-center s-space-x-2">
<RadioGroupItem value="option-two" id="option-two" />
<Label htmlFor="option-two">Option Two</Label>
<RadioGroupItem
value="option-two"
id="option-two"
label={<Label htmlFor="option-two">Option Two</Label>}
/>
</div>
<div className="s-flex s-items-center s-space-x-2">
<RadioGroupItem value="option-three" id="option-three" />
<Label htmlFor="option-two">Option Three</Label>
<RadioGroupItem
value="option-three"
id="option-three"
label={<Label htmlFor="option-two">Option Three</Label>}
/>
</div>
</RadioGroup>
<RadioGroup defaultValue="option-one">
Expand All @@ -40,21 +50,25 @@ export const RadioGroupExample = () => {
id="option-four"
size="sm"
tooltipMessage="This is a nice tooltip message"
label={<Label htmlFor="option-one">Option One</Label>}
/>
<Label htmlFor="option-one">Option One</Label>
</div>
<div className="s-flex s-items-center s-space-x-2">
<RadioGroupItem
value="option-two"
id="option-five"
size="sm"
disabled
label={<Label htmlFor="option-two">Option Two</Label>}
/>
<Label htmlFor="option-two">Option Two</Label>
</div>
<div className="s-flex s-items-center s-space-x-2">
<RadioGroupItem value="option-six" id="option-three" size="sm" />
<Label htmlFor="option-three">Option Three</Label>
<RadioGroupItem
value="option-six"
id="option-three"
size="sm"
label={<Label htmlFor="option-three">Option Three</Label>}
/>
</div>
</RadioGroup>
</div>
Expand All @@ -77,9 +91,18 @@ export const RadioGroupWithChildrenExample = () => {
onValueChange={(value) => setSelectedChoice(value)}
>
{choices.map((choice) => (
<RadioGroupChoice value={choice.id} iconPosition="start">
<RadioGroupChoice
value={choice.id}
iconPosition="start"
label={
<div className="s-flex s-items-center s-gap-2">
<Icon visual={LockIcon} />
<Label>{choice.label}</Label>
</div>
}
>
<div className="s-flex s-items-center s-gap-2 s-border s-border-red-500 s-p-2">
<Icon visual={LockIcon} />
<Icon visual={FolderIcon} />
<Label>{choice.label}</Label>
<Button label="Click me" />
</div>
Expand Down

0 comments on commit 45af7db

Please sign in to comment.