Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/frontend/packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-toast": "^1.2.4",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@tanstack/react-table": "^8.20.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/packages/ui/src/components/Toggle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Toggle } from './toggle';
44 changes: 44 additions & 0 deletions src/frontend/packages/ui/src/components/Toggle/toggle.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Toggle } from './toggle';
import { Mic, MicOff } from 'lucide-react';
import { useState } from 'react';

const meta: Meta<typeof Toggle> = {
title: 'Widget/Toggle',
component: Toggle,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'outline'],
},
size: {
control: 'radio',
options: ['default', 'lg'],
},
},
};
export default meta;
type Story = StoryObj<typeof Toggle>;

export const Default: Story = {
args: {
variant: 'outline',
size: 'default',
},
render: (args) => {
const [isPressed, setIsPressed] = useState(false);
return (
<Toggle
{...args}
pressed={isPressed}
onPressedChange={setIsPressed}
>
{isPressed ? <Mic /> : <MicOff />}
</Toggle>
);
},
};
40 changes: 40 additions & 0 deletions src/frontend/packages/ui/src/components/Toggle/toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use client';

import * as React from 'react';
import * as TogglePrimitive from '@radix-ui/react-toggle';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@workspace/ui/lib/utils';

const toggleVariants = cva(
'inline-flex items-center justify-center rounded-full text-sm font-medium text-muted-foreground ring-offset-background transition-colors hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2',
{
variants: {
variant: {
default: 'bg-transparent',
outline: 'border border-input bg-transparent hover:text-accent-foreground',
},
size: {
default: 'w-10 h-10 px-3',
lg: 'w-12 h-12 px-5',
},
},
defaultVariants: {
variant: 'outline',
size: 'default',
},
},
);

const Toggle = React.forwardRef<React.ElementRef<typeof TogglePrimitive.Root>, React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>>(
({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
),
);

Toggle.displayName = TogglePrimitive.Root.displayName;

export { Toggle, toggleVariants };
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ToggleGroup, ToggleGroupItem } from './toggle-group';
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ToggleGroup, ToggleGroupItem } from './toggle-group';
import { useState } from 'react';
import { Mic, MicOff, ScreenShare, ScreenShareOff, Video, VideoOff } from 'lucide-react';

const meta: Meta<typeof ToggleGroup> = {
title: 'Widget/ToggleGroup',
component: ToggleGroup,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof ToggleGroup>;

export const Default: Story = {
render: () => {
const [isMicOn, setIsMicOn] = useState(false);
const [isVideoOn, setIsVideoOn] = useState(false);
const [isScreenSharing, setIsScreenSharing] = useState(false);

return (
<ToggleGroup
variant="outline"
type="multiple"
>
<ToggleGroupItem
value="mic"
onClick={() => setIsMicOn((prev) => !prev)}
>
{isMicOn ? <Mic /> : <MicOff />}
</ToggleGroupItem>
<ToggleGroupItem
value="video"
onClick={() => setIsVideoOn((prev) => !prev)}
>
{isVideoOn ? <Video /> : <VideoOff />}
</ToggleGroupItem>
<ToggleGroupItem
value="sharing"
onClick={() => setIsScreenSharing((prev) => !prev)}
>
{isScreenSharing ? <ScreenShare /> : <ScreenShareOff />}
</ToggleGroupItem>
</ToggleGroup>
);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';

import * as React from 'react';
import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
import { type VariantProps } from 'class-variance-authority';

import { cn } from '@workspace/ui/lib/utils';
import { toggleVariants } from '../Toggle/toggle';

const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
size: 'default',
variant: 'outline',
});

const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> & VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn('flex items-center justify-center gap-1', className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
));

ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;

const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext);

return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
}),
className,
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
);
});

ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;

export { ToggleGroup, ToggleGroupItem };
2 changes: 2 additions & 0 deletions src/frontend/packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export * from './Toast';
export * from './Resizable';
export * from './Avatar';
export * from './Separate';
export * from './Toggle';
export * from './ToggleGroup';
119 changes: 119 additions & 0 deletions src/frontend/pnpm-lock.yaml

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

Loading