From deaa6dfd74738eae384b4de0a28c60b6af4a4883 Mon Sep 17 00:00:00 2001
From: Rob Di Marco
Date: Fri, 23 Jan 2026 11:28:49 -0500
Subject: [PATCH 1/9] Add user management components for model and participant
selection
Implements four new components based on Figma designs:
1. Tooltip - Hover tooltips for UI elements
- Simple popover with text
- Uses popover theme tokens
- Proper ARIA role for accessibility
2. DropdownMenu - Standalone dropdown menus
- Menu items with icons and avatars
- Secondary icons (check, plus, chevron)
- Separator and label support
- Search input integration
- Hover and active states
3. AvatarGroup - Overlapping user avatars
- Negative margin overlap design
- Border separation for clarity
- Presence indicator support
- Size variants (sm, default, lg)
- Spacing variants (tight, default, loose)
4. ModelUserManagement - Complete compound component
- Model selector button
- Add user button
- Avatar display (single or group)
- User dropdown trigger
- Integrates all sub-components
Features:
- TypeScript with proper prop types
- class-variance-authority for variants
- Comprehensive Storybook stories
- Exported from src/index.ts
- Vanilla HTML/CSS examples in vanilla/components/user-management.html
- Updated vanilla/index.html with new component links
Based on Figma: https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5077-6876
---
.../AvatarGroup/AvatarGroup.stories.tsx | 129 ++++++++
src/components/AvatarGroup/AvatarGroup.tsx | 102 ++++++
src/components/AvatarGroup/index.ts | 7 +
.../DropdownMenu/DropdownMenu.stories.tsx | 259 +++++++++++++++
src/components/DropdownMenu/DropdownMenu.tsx | 186 +++++++++++
src/components/DropdownMenu/index.ts | 11 +
.../ModelUserManagement.stories.tsx | 162 ++++++++++
.../ModelUserManagement.tsx | 157 +++++++++
src/components/ModelUserManagement/index.ts | 14 +
src/components/Tooltip/Tooltip.stories.tsx | 42 +++
src/components/Tooltip/Tooltip.tsx | 40 +++
src/components/Tooltip/index.ts | 1 +
src/index.ts | 4 +
vanilla/components/user-management.html | 300 ++++++++++++++++++
vanilla/index.html | 8 +-
15 files changed, 1421 insertions(+), 1 deletion(-)
create mode 100644 src/components/AvatarGroup/AvatarGroup.stories.tsx
create mode 100644 src/components/AvatarGroup/AvatarGroup.tsx
create mode 100644 src/components/AvatarGroup/index.ts
create mode 100644 src/components/DropdownMenu/DropdownMenu.stories.tsx
create mode 100644 src/components/DropdownMenu/DropdownMenu.tsx
create mode 100644 src/components/DropdownMenu/index.ts
create mode 100644 src/components/ModelUserManagement/ModelUserManagement.stories.tsx
create mode 100644 src/components/ModelUserManagement/ModelUserManagement.tsx
create mode 100644 src/components/ModelUserManagement/index.ts
create mode 100644 src/components/Tooltip/Tooltip.stories.tsx
create mode 100644 src/components/Tooltip/Tooltip.tsx
create mode 100644 src/components/Tooltip/index.ts
create mode 100644 vanilla/components/user-management.html
diff --git a/src/components/AvatarGroup/AvatarGroup.stories.tsx b/src/components/AvatarGroup/AvatarGroup.stories.tsx
new file mode 100644
index 0000000..37b70d4
--- /dev/null
+++ b/src/components/AvatarGroup/AvatarGroup.stories.tsx
@@ -0,0 +1,129 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { AvatarGroup, AvatarGroupItem } from './AvatarGroup';
+
+const meta = {
+ title: 'Components/AvatarGroup',
+ component: AvatarGroup,
+ parameters: {
+ layout: 'centered',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5069-7627',
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Single: Story = {
+ render: () => (
+
+
+
+ ),
+};
+
+export const Two: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const Three: Story = {
+ render: () => (
+
+
+
+
+
+ ),
+};
+
+export const WithPresenceIndicator: Story = {
+ render: () => (
+
+
+
+ ),
+};
+
+export const TwoWithPresence: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const SmallSize: Story = {
+ render: () => (
+
+
+
+
+
+ ),
+};
+
+export const LargeSize: Story = {
+ render: () => (
+
+
+
+
+
+ ),
+};
+
+export const TightSpacing: Story = {
+ render: () => (
+
+
+
+
+
+
+ ),
+};
+
+export const LooseSpacing: Story = {
+ render: () => (
+
+
+
+
+
+
+ ),
+};
+
+export const WithImages: Story = {
+ render: () => (
+
+
+
+
+
+ ),
+};
diff --git a/src/components/AvatarGroup/AvatarGroup.tsx b/src/components/AvatarGroup/AvatarGroup.tsx
new file mode 100644
index 0000000..2e71a71
--- /dev/null
+++ b/src/components/AvatarGroup/AvatarGroup.tsx
@@ -0,0 +1,102 @@
+import * as React from 'react';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { cn } from '@/lib/utils';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/Avatar';
+
+/**
+ * AvatarGroup Component
+ *
+ * Displays multiple user avatars in an overlapping group.
+ * Each avatar shows with a border for visual separation.
+ * Based on Figma component: https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5069-7627
+ *
+ * @example
+ * ```tsx
+ *
+ *
+ *
+ *
+ *
+ * ```
+ */
+
+const avatarGroupVariants = cva('flex items-center', {
+ variants: {
+ size: {
+ sm: '[&>*]:h-4 [&>*]:w-4 [&>*]:text-[10px]',
+ default: '[&>*]:h-[25px] [&>*]:w-[25px] [&>*]:text-xs',
+ lg: '[&>*]:h-10 [&>*]:w-10 [&>*]:text-sm',
+ },
+ spacing: {
+ tight: '[&>*:not(:first-child)]:-ml-2',
+ default: '[&>*:not(:first-child)]:-ml-1',
+ loose: '[&>*:not(:first-child)]:-ml-0.5',
+ },
+ },
+ defaultVariants: {
+ size: 'default',
+ spacing: 'default',
+ },
+});
+
+export interface AvatarGroupProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+
+const AvatarGroup = React.forwardRef(
+ ({ className, size, spacing, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+AvatarGroup.displayName = 'AvatarGroup';
+
+export interface AvatarGroupItemProps
+ extends Omit, 'children'> {
+ /**
+ * URL of the avatar image
+ */
+ src?: string;
+ /**
+ * Alt text for the avatar image
+ */
+ alt?: string;
+ /**
+ * Fallback text (usually initials)
+ */
+ fallback: string;
+ /**
+ * Whether to show a presence indicator (green dot)
+ */
+ showPresence?: boolean;
+}
+
+const AvatarGroupItem = React.forwardRef(
+ ({ className, src, alt, fallback, showPresence, ...props }, ref) => {
+ return (
+
+
+ {src && }
+
+ {fallback}
+
+
+ {showPresence && (
+
+ )}
+
+ );
+ }
+);
+AvatarGroupItem.displayName = 'AvatarGroupItem';
+
+export { AvatarGroup, AvatarGroupItem, avatarGroupVariants };
diff --git a/src/components/AvatarGroup/index.ts b/src/components/AvatarGroup/index.ts
new file mode 100644
index 0000000..2361268
--- /dev/null
+++ b/src/components/AvatarGroup/index.ts
@@ -0,0 +1,7 @@
+export {
+ AvatarGroup,
+ AvatarGroupItem,
+ avatarGroupVariants,
+ type AvatarGroupProps,
+ type AvatarGroupItemProps,
+} from './AvatarGroup';
diff --git a/src/components/DropdownMenu/DropdownMenu.stories.tsx b/src/components/DropdownMenu/DropdownMenu.stories.tsx
new file mode 100644
index 0000000..1f4f81f
--- /dev/null
+++ b/src/components/DropdownMenu/DropdownMenu.stories.tsx
@@ -0,0 +1,259 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { DropdownMenu, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator } from './DropdownMenu';
+import { Avatar, AvatarFallback } from '@/components/Avatar';
+import { Input } from '@/components/Input';
+import { Users, Edit2 } from 'lucide-react';
+
+const meta = {
+ title: 'Components/DropdownMenu',
+ component: DropdownMenu,
+ parameters: {
+ layout: 'centered',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5070-8203',
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const AddParticipants: Story = {
+ render: () => (
+
+ Add participants
+ Group
+ Team member
+
+ ),
+};
+
+export const SelectModel: Story = {
+ render: () => (
+
+
+ A
+
+ }
+ checked
+ >
+ Claude Opus 4.5
+
+
+ A
+
+ }
+ >
+ Claude Sonnet 4.5
+
+
+ G
+
+ }
+ secondaryIcon="plus"
+ >
+ Gemini 3 Pro
+
+
+ G
+
+ }
+ secondaryIcon="plus"
+ >
+ Gemini Flash
+
+
+ O
+
+ }
+ secondaryIcon="plus"
+ >
+ GPT-5.1 Codex
+
+
+ O
+
+ }
+ secondaryIcon="plus"
+ >
+ GPT-5.2
+
+
+ O
+
+ }
+ secondaryIcon="plus"
+ >
+ GPT-5.2 Pro
+
+
+ O
+
+ }
+ secondaryIcon="plus"
+ >
+ o4-mini
+
+
+ ),
+};
+
+export const AddGroup: Story = {
+ render: () => (
+
+ Add group
+
+
+
+
+
+ Dev team
+
+
+ Leadership
+
+
+ Prod/Dev
+
+
+ Create new group
+
+ ),
+};
+
+export const AddTeamMember: Story = {
+ render: () => (
+
+ Add team member
+
+
+
+
+
+
+ B
+
+
+ }
+ secondaryIcon="plus"
+ >
+ Brittan Berry
+
+
+ D
+
+ }
+ secondaryIcon="plus"
+ >
+ David Noël-Romas
+
+
+ E
+
+ }
+ secondaryIcon="plus"
+ >
+ Emilio
+
+
+ L
+
+ }
+ secondaryIcon="plus"
+ >
+ Louis Amira
+
+
+ N
+
+ }
+ secondaryIcon="plus"
+ >
+ Naveen
+
+
+ R
+
+ }
+ secondaryIcon="plus"
+ >
+ Rob D
+
+
+ ),
+};
+
+export const ViewParticipants: Story = {
+ render: () => (
+
+
+ L
+
+ }
+ >
+ Lucy Cameron
+
+
+ B
+
+ }
+ secondaryIcon="plus"
+ >
+ Brian DeJong
+
+
+ R
+
+ }
+ secondaryIcon="plus"
+ >
+ Rob Di Marco
+
+
+ ),
+};
+
+export const RemoveUser: Story = {
+ render: () => (
+
+ Remove
+
+ ),
+};
diff --git a/src/components/DropdownMenu/DropdownMenu.tsx b/src/components/DropdownMenu/DropdownMenu.tsx
new file mode 100644
index 0000000..e57f807
--- /dev/null
+++ b/src/components/DropdownMenu/DropdownMenu.tsx
@@ -0,0 +1,186 @@
+import * as React from 'react';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { cn } from '@/lib/utils';
+import { Icon, Check, Plus, ChevronRight } from '@/components/Icon';
+import type { LucideIcon } from 'lucide-react';
+
+/**
+ * DropdownMenu Component
+ *
+ * Displays a menu to the user — such as a set of actions or functions — triggered by a button.
+ * Based on Figma component: https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5070-8203
+ *
+ * @see https://ui.shadcn.com/docs/components/dropdown-menu
+ *
+ * @example
+ * ```tsx
+ *
+ * Add participants
+ * Group
+ * Team member
+ *
+ * ```
+ */
+
+export type DropdownMenuProps = React.HTMLAttributes;
+
+const DropdownMenu = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+DropdownMenu.displayName = 'DropdownMenu';
+
+const dropdownMenuItemVariants = cva(
+ 'flex h-8 w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm font-normal leading-5 text-popover-foreground transition-colors',
+ {
+ variants: {
+ variant: {
+ default: 'hover:bg-muted',
+ active: 'bg-muted',
+ },
+ disabled: {
+ true: 'cursor-not-allowed opacity-50',
+ false: 'cursor-pointer',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ disabled: false,
+ },
+ }
+);
+
+export interface DropdownMenuItemProps
+ extends Omit, 'disabled'>,
+ VariantProps {
+ /**
+ * Optional icon to display on the left
+ */
+ icon?: LucideIcon;
+ /**
+ * Optional secondary icon to display on the right
+ */
+ secondaryIcon?: LucideIcon | 'check' | 'plus' | 'chevron';
+ /**
+ * Whether to show a checkmark (shorthand for secondaryIcon="check")
+ */
+ checked?: boolean;
+ /**
+ * Whether this item has a submenu (shorthand for secondaryIcon="chevron")
+ */
+ hasSubmenu?: boolean;
+ /**
+ * Optional avatar element to display instead of icon
+ */
+ avatar?: React.ReactNode;
+}
+
+const DropdownMenuItem = React.forwardRef<
+ HTMLButtonElement,
+ DropdownMenuItemProps
+>(
+ (
+ {
+ className,
+ variant,
+ disabled = false,
+ icon,
+ secondaryIcon,
+ checked,
+ hasSubmenu,
+ avatar,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const isDisabled = Boolean(disabled);
+
+ // Determine secondary icon
+ let secondaryIconComponent: React.ReactNode = null;
+ if (checked || secondaryIcon === 'check') {
+ secondaryIconComponent = ;
+ } else if (hasSubmenu || secondaryIcon === 'chevron') {
+ secondaryIconComponent = ;
+ } else if (secondaryIcon === 'plus') {
+ secondaryIconComponent = ;
+ } else if (secondaryIcon && typeof secondaryIcon !== 'string') {
+ secondaryIconComponent = ;
+ }
+
+ return (
+
+ );
+ }
+);
+DropdownMenuItem.displayName = 'DropdownMenuItem';
+
+export type DropdownMenuLabelProps = React.HTMLAttributes;
+
+const DropdownMenuLabel = React.forwardRef<
+ HTMLDivElement,
+ DropdownMenuLabelProps
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+DropdownMenuLabel.displayName = 'DropdownMenuLabel';
+
+export type DropdownMenuSeparatorProps = React.HTMLAttributes;
+
+const DropdownMenuSeparator = React.forwardRef<
+ HTMLDivElement,
+ DropdownMenuSeparatorProps
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+DropdownMenuSeparator.displayName = 'DropdownMenuSeparator';
+
+export {
+ DropdownMenu,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ dropdownMenuItemVariants,
+};
diff --git a/src/components/DropdownMenu/index.ts b/src/components/DropdownMenu/index.ts
new file mode 100644
index 0000000..fb2f2ac
--- /dev/null
+++ b/src/components/DropdownMenu/index.ts
@@ -0,0 +1,11 @@
+export {
+ DropdownMenu,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ dropdownMenuItemVariants,
+ type DropdownMenuProps,
+ type DropdownMenuItemProps,
+ type DropdownMenuLabelProps,
+ type DropdownMenuSeparatorProps,
+} from './DropdownMenu';
diff --git a/src/components/ModelUserManagement/ModelUserManagement.stories.tsx b/src/components/ModelUserManagement/ModelUserManagement.stories.tsx
new file mode 100644
index 0000000..4b3259d
--- /dev/null
+++ b/src/components/ModelUserManagement/ModelUserManagement.stories.tsx
@@ -0,0 +1,162 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import {
+ ModelUserManagement,
+ ModelSelector,
+ UserManagementGroup,
+ AddUserButton,
+ UserAvatars,
+ UserDropdownTrigger,
+} from './ModelUserManagement';
+import { AvatarGroupItem } from '@/components/AvatarGroup';
+
+const meta = {
+ title: 'Components/ModelUserManagement',
+ component: ModelUserManagement,
+ parameters: {
+ layout: 'centered',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5070-8794',
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+ Claude Sonnet 4.5
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const TwoUsers: Story = {
+ render: () => (
+
+ Claude Sonnet 4.5
+
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const ThreeUsers: Story = {
+ render: () => (
+
+ Claude Sonnet 4.5
+
+
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const WithPresenceIndicator: Story = {
+ render: () => (
+
+ Claude Sonnet 4.5
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const TwoUsersWithPresence: Story = {
+ render: () => (
+
+ Claude Sonnet 4.5
+
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const DifferentModel: Story = {
+ render: () => (
+
+ Claude Opus 4.5
+
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const SingleUserNoPresence: Story = {
+ render: () => (
+
+ GPT-5.2 Pro
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const WithCustomHandlers: Story = {
+ render: () => (
+
+ alert('Select model')}>
+ Claude Sonnet 4.5
+
+
+ alert('Add user')} />
+
+
+
+
+ alert('User options')} />
+
+
+ ),
+};
diff --git a/src/components/ModelUserManagement/ModelUserManagement.tsx b/src/components/ModelUserManagement/ModelUserManagement.tsx
new file mode 100644
index 0000000..f53e777
--- /dev/null
+++ b/src/components/ModelUserManagement/ModelUserManagement.tsx
@@ -0,0 +1,157 @@
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+import { Button } from '@/components/Button';
+import { AvatarGroup } from '@/components/AvatarGroup';
+import { Icon, Plus, ChevronDown } from '@/components/Icon';
+
+/**
+ * ModelUserManagement Component
+ *
+ * A compound component for managing model selection and user participants.
+ * Combines model selector button with user management controls including
+ * add user button, avatar display, and user dropdown.
+ * Based on Figma component: https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=5070-8794
+ *
+ * @example
+ * ```tsx
+ *
+ * Claude Sonnet 4.5
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ */
+
+export type ModelUserManagementProps = React.HTMLAttributes;
+
+const ModelUserManagement = React.forwardRef<
+ HTMLDivElement,
+ ModelUserManagementProps
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+ModelUserManagement.displayName = 'ModelUserManagement';
+
+export interface ModelSelectorProps
+ extends React.ButtonHTMLAttributes {}
+
+const ModelSelector = React.forwardRef(
+ ({ className, children, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+ModelSelector.displayName = 'ModelSelector';
+
+export type UserManagementGroupProps = React.HTMLAttributes;
+
+const UserManagementGroup = React.forwardRef<
+ HTMLDivElement,
+ UserManagementGroupProps
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+UserManagementGroup.displayName = 'UserManagementGroup';
+
+export interface AddUserButtonProps
+ extends React.ButtonHTMLAttributes {}
+
+const AddUserButton = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+AddUserButton.displayName = 'AddUserButton';
+
+export type UserAvatarsProps = React.HTMLAttributes;
+
+const UserAvatars = React.forwardRef(
+ ({ className, children, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+UserAvatars.displayName = 'UserAvatars';
+
+export interface UserDropdownTriggerProps
+ extends React.ButtonHTMLAttributes {}
+
+const UserDropdownTrigger = React.forwardRef<
+ HTMLButtonElement,
+ UserDropdownTriggerProps
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+UserDropdownTrigger.displayName = 'UserDropdownTrigger';
+
+export {
+ ModelUserManagement,
+ ModelSelector,
+ UserManagementGroup,
+ AddUserButton,
+ UserAvatars,
+ UserDropdownTrigger,
+};
diff --git a/src/components/ModelUserManagement/index.ts b/src/components/ModelUserManagement/index.ts
new file mode 100644
index 0000000..2110dc4
--- /dev/null
+++ b/src/components/ModelUserManagement/index.ts
@@ -0,0 +1,14 @@
+export {
+ ModelUserManagement,
+ ModelSelector,
+ UserManagementGroup,
+ AddUserButton,
+ UserAvatars,
+ UserDropdownTrigger,
+ type ModelUserManagementProps,
+ type ModelSelectorProps,
+ type UserManagementGroupProps,
+ type AddUserButtonProps,
+ type UserAvatarsProps,
+ type UserDropdownTriggerProps,
+} from './ModelUserManagement';
diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx
new file mode 100644
index 0000000..915fe41
--- /dev/null
+++ b/src/components/Tooltip/Tooltip.stories.tsx
@@ -0,0 +1,42 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Tooltip } from './Tooltip';
+
+const meta = {
+ title: 'Components/Tooltip',
+ component: Tooltip,
+ parameters: {
+ layout: 'centered',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=2688-451',
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ children: 'Chat participants',
+ },
+};
+
+export const AddParticipants: Story = {
+ args: {
+ children: 'Add participants',
+ },
+};
+
+export const SelectModel: Story = {
+ args: {
+ children: 'Select model',
+ },
+};
+
+export const LongText: Story = {
+ args: {
+ children: 'This is a longer tooltip text that might wrap to multiple lines',
+ },
+};
diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx
new file mode 100644
index 0000000..cb5275d
--- /dev/null
+++ b/src/components/Tooltip/Tooltip.tsx
@@ -0,0 +1,40 @@
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+
+/**
+ * Tooltip Component
+ *
+ * A popup that displays information related to an element when the element
+ * receives keyboard focus or the mouse hovers over it.
+ * Based on Figma component: https://www.figma.com/design/nadcKNlrnZUHbbLwm9GdK4?node-id=2688-451
+ *
+ * @see https://ui.shadcn.com/docs/components/tooltip
+ *
+ * @example
+ * ```tsx
+ *
+ * Chat participants
+ *
+ * ```
+ */
+
+export type TooltipProps = React.HTMLAttributes;
+
+const Tooltip = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ );
+ }
+);
+Tooltip.displayName = 'Tooltip';
+
+export { Tooltip };
diff --git a/src/components/Tooltip/index.ts b/src/components/Tooltip/index.ts
new file mode 100644
index 0000000..e84d44a
--- /dev/null
+++ b/src/components/Tooltip/index.ts
@@ -0,0 +1 @@
+export { Tooltip, type TooltipProps } from './Tooltip';
diff --git a/src/index.ts b/src/index.ts
index bd9bdd2..2358540 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,6 +3,7 @@ export * from './components/Accordion';
export * from './components/Alert';
export * from './components/AlertDialog';
export * from './components/Avatar';
+export * from './components/AvatarGroup';
export * from './components/Badge';
export * from './components/Breadcrumb';
export * from './components/Button';
@@ -12,6 +13,7 @@ export * from './components/Carousel';
export * from './components/Checkbox';
export * from './components/Dialog';
export * from './components/Drawer';
+export * from './components/DropdownMenu';
export * from './components/Header';
export * from './components/HoverCard';
export * from './components/Icon';
@@ -20,6 +22,7 @@ export * from './components/Input';
export * from './components/InputGroup';
export * from './components/Label';
export * from './components/Menubar';
+export * from './components/ModelUserManagement';
export * from './components/NavHeader';
export * from './components/NavSidePanel';
export * from './components/Pagination';
@@ -37,6 +40,7 @@ export * from './components/Tabs';
export * from './components/Textarea';
export * from './components/Toast';
export * from './components/Toggle';
+export * from './components/Tooltip';
// Utilities
export { cn } from './lib/utils';
diff --git a/vanilla/components/user-management.html b/vanilla/components/user-management.html
new file mode 100644
index 0000000..a9eea1c
--- /dev/null
+++ b/vanilla/components/user-management.html
@@ -0,0 +1,300 @@
+
+
+
+
+
+ User Management Components - ATXP Design System
+
+
+
+
+
+
+
+
+
+ Tooltip
+ A popup that displays information related to an element.
+
+
+
+ Chat participants
+
+
+
+ Add participants
+
+
+
+ Select model
+
+
+
+
+
+
+ Avatar Group
+ Multiple user avatars displayed in an overlapping group.
+
+
+
+
+
+
+
+
+
+
With Presence Indicator
+
+
+
+
+
+
+
+ Dropdown Menu
+ Displays a menu to the user with actions or functions.
+
+
+
+
+
+ Add participants
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model & User Management
+ Complete model selection and user management interface.
+
+
+
+
Single User
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Two Users
+
+
+
+
+
+
+
+
+
Three Users
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vanilla/index.html b/vanilla/index.html
index addd161..5a05046 100644
--- a/vanilla/index.html
+++ b/vanilla/index.html
@@ -434,6 +434,11 @@ Detailed Component Examples
Interactive
Tabs, accordions, progress, skeletons
+
+
+ User Management
+ Model selection, tooltips, dropdowns, avatar groups
+
@@ -524,7 +529,8 @@
From 34e747c86cddb33f900ca13361327b0c9e5796a2 Mon Sep 17 00:00:00 2001
From: Rob Di Marco
Date: Fri, 23 Jan 2026 12:09:52 -0500
Subject: [PATCH 2/9] Fix avatar sizes and vertical alignment in user
management components
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Add tailwind-merge to cn utility to properly handle conflicting Tailwind classes
- Fix avatar text size in dropdown menus: text-xs (12px) → text-[10px] for 16px avatars
- Fix vertical alignment in ModelUserManagement by setting explicit height on UserAvatars
- Convert empty interfaces to type aliases to fix TypeScript lint errors
This ensures:
- Small avatars (16px) in dropdowns render at correct size and don't inherit 40px default
- All components in ModelUserManagement are properly vertically centered
- Text in small avatars is proportional (10px text in 16px avatars)
- Code passes TypeScript linting without empty interface warnings
---
package.json | 15 +--
pnpm-lock.yaml | 110 ++++++++++--------
.../DropdownMenu/DropdownMenu.stories.tsx | 34 +++---
.../ModelUserManagement.tsx | 11 +-
src/lib/utils.ts | 6 +-
5 files changed, 92 insertions(+), 84 deletions(-)
diff --git a/package.json b/package.json
index 87b9100..4c48ce0 100644
--- a/package.json
+++ b/package.json
@@ -49,17 +49,17 @@
"homepage": "https://github.com/atxp-dev/design-system#readme",
"sideEffects": false,
"peerDependencies": {
+ "lucide-react": "^0.562.0",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0",
- "lucide-react": "^0.562.0",
"sonner": "^2.0.7"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
- "@storybook/addon-designs": "^11.1.0",
- "@storybook/addon-links": "^10.1.10",
- "@storybook/react": "^10.1.10",
- "@storybook/react-vite": "^10.1.10",
+ "@storybook/addon-designs": "^11.1.1",
+ "@storybook/addon-links": "^10.2.0",
+ "@storybook/react": "^10.2.0",
+ "@storybook/react-vite": "^10.2.0",
"@tailwindcss/cli": "^4.1.18",
"@tailwindcss/postcss": "^4.1.18",
"@types/react": "^19.2.7",
@@ -75,7 +75,7 @@
"postcss": "^8.5.6",
"react": "^19.2.3",
"react-dom": "^19.2.3",
- "storybook": "^10.1.10",
+ "storybook": "^10.2.0",
"tailwindcss": "^4.1.18",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
@@ -90,7 +90,8 @@
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1"
+ "clsx": "^2.1.1",
+ "tailwind-merge": "^3.4.0"
},
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f70e5b8..a8f5509 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,22 +41,25 @@ importers:
sonner:
specifier: ^2.0.7
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ tailwind-merge:
+ specifier: ^3.4.0
+ version: 3.4.0
devDependencies:
'@eslint/js':
specifier: ^9.39.2
version: 9.39.2
'@storybook/addon-designs':
- specifier: ^11.1.0
- version: 11.1.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
+ specifier: ^11.1.1
+ version: 11.1.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
'@storybook/addon-links':
- specifier: ^10.1.10
- version: 10.1.10(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
+ specifier: ^10.2.0
+ version: 10.2.0(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
'@storybook/react':
- specifier: ^10.1.10
- version: 10.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
+ specifier: ^10.2.0
+ version: 10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
'@storybook/react-vite':
- specifier: ^10.1.10
- version: 10.1.10(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
+ specifier: ^10.2.0
+ version: 10.2.0(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
'@tailwindcss/cli':
specifier: ^4.1.18
version: 4.1.18
@@ -103,8 +106,8 @@ importers:
specifier: ^19.2.3
version: 19.2.3(react@19.2.3)
storybook:
- specifier: ^10.1.10
- version: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ specifier: ^10.2.0
+ version: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
tailwindcss:
specifier: ^4.1.18
version: 4.1.18
@@ -1087,8 +1090,8 @@ packages:
cpu: [x64]
os: [win32]
- '@storybook/addon-designs@11.1.0':
- resolution: {integrity: sha512-i9lnUJ9x+UwThUpIjgg7QWvadhwmQ1ZuqcrTFe12giqyyYJKM6hdrUEuxGgSOrz3pkmDV/Bypq3G5ehwIDdKiw==}
+ '@storybook/addon-designs@11.1.1':
+ resolution: {integrity: sha512-1KAmTzoW/qw4RfR8uft3pBgsdWHoQiMp9rt+nzhFLEBPd1Ru3YiTnVL/JBEiJkGXsQfQxMnAYRRwYgf+HTr4yw==}
peerDependencies:
'@storybook/addon-docs': ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -1102,27 +1105,27 @@ packages:
react-dom:
optional: true
- '@storybook/addon-links@10.1.10':
- resolution: {integrity: sha512-SVKFDb14mne16QMGkmOEk+T4NLvCuFJJ1ecebQ01cPiG5gM72LhzYkAro717Aizd6owyMqcWs0Rsfwl09qi5zA==}
+ '@storybook/addon-links@10.2.0':
+ resolution: {integrity: sha512-QOZLlcJwK6RkhizxBqDzipfYNqVrQNbWMFLHDcSfdA7suszgelxLyUVK9pC0McMmkpjw14bMH22urLjrjHUOuw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- storybook: ^10.1.10
+ storybook: ^10.2.0
peerDependenciesMeta:
react:
optional: true
- '@storybook/builder-vite@10.1.10':
- resolution: {integrity: sha512-6m6zOyDhHLynv3lvkH70s1YoIkIFPhbpGsBKvHchRLrZLe8hCPeafIFLfZRPoD4yIPwBS6rWbjMsSvBMFlR+ag==}
+ '@storybook/builder-vite@10.2.0':
+ resolution: {integrity: sha512-S1+62ipGmQzGPZfcbgNqpbrCezsqkvbhj+MBbQ6VS46b2HcPjm4H8V6FzGly0Ja2pSgu8gT1BQ5N+3yOG8UNTw==}
peerDependencies:
- storybook: ^10.1.10
+ storybook: ^10.2.0
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
- '@storybook/csf-plugin@10.1.10':
- resolution: {integrity: sha512-2dri4TRU8uuj/skmx/ZBw+GnnXf8EZHiMDMeijVRdBQtYFWPeoYzNIrGRpNfbuGpnDP0dcxrqti/TsedoxwFkA==}
+ '@storybook/csf-plugin@10.2.0':
+ resolution: {integrity: sha512-Cty+tZ0r1AZhwBBzqI4RyCpMVGt9wHGTtG4YCRUuNgVFO1MnjaFBHKRT+oT7md28+BWYjFz4Qtpge/fcWANJ0w==}
peerDependencies:
esbuild: '*'
rollup: '*'
- storybook: ^10.1.10
+ storybook: ^10.2.0
vite: '*'
webpack: '*'
peerDependenciesMeta:
@@ -1144,27 +1147,27 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- '@storybook/react-dom-shim@10.1.10':
- resolution: {integrity: sha512-9pmUbEr1MeMHg9TG0c2jVUfHWr2AA86vqZGphY/nT6mbe/rGyWtBl5EnFLrz6WpI8mo3h+Kxs6p2oiuIYieRtw==}
+ '@storybook/react-dom-shim@10.2.0':
+ resolution: {integrity: sha512-PEQofiruE6dBGzUQPXZZREbuh1t62uRBWoUPRFNAZi79zddlk7+b9qu08VV9cvf68mwOqqT1+VJ1P+3ClD2ZVw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- storybook: ^10.1.10
+ storybook: ^10.2.0
- '@storybook/react-vite@10.1.10':
- resolution: {integrity: sha512-6kE4/88YuwO07P0DR6caKNDNvCB/VnpimPmj4Jv6qmqrBgnoOOiXHIKyHJD+EjNyrbbwv4ygG01RVEajpjQaDA==}
+ '@storybook/react-vite@10.2.0':
+ resolution: {integrity: sha512-tIXRfrA+wREFuA+bIJccMCV1YVFdACENcSnSlnB5Be3m8ynMHukOz6ObX9jI5WsWZnqrk0/eHyiYJyVhpY9rhQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- storybook: ^10.1.10
+ storybook: ^10.2.0
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
- '@storybook/react@10.1.10':
- resolution: {integrity: sha512-9Rpr8/wX0p5/EaulrxpqrjKjhGaA/Ab9HgxzTqs2Shz0gvMAQHoiRnTEp7RCCkP49ruFYnIp0yGRSovu03LakQ==}
+ '@storybook/react@10.2.0':
+ resolution: {integrity: sha512-ciJlh1UGm0GBXQgqrYFeLmiix+KGFB3v37OnAYjGghPS9OP6S99XyshxY/6p0sMOYtS+eWS2gPsOKNXNnLDGYw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- storybook: ^10.1.10
+ storybook: ^10.2.0
typescript: '>= 4.9.x'
peerDependenciesMeta:
typescript:
@@ -2682,8 +2685,8 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
- storybook@10.1.10:
- resolution: {integrity: sha512-oK0t0jEogiKKfv5Z1ao4Of99+xWw1TMUGuGRYDQS4kp2yyBsJQEgu7NI7OLYsCDI6gzt5p3RPtl1lqdeVLUi8A==}
+ storybook@10.2.0:
+ resolution: {integrity: sha512-fIQnFtpksRRgHR1CO1onGX3djaog4qsW/c5U8arqYTkUEr2TaWpn05mIJDOBoPJFlOdqFrB4Ttv0PZJxV7avhw==}
hasBin: true
peerDependencies:
prettier: ^2 || ^3
@@ -2755,6 +2758,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ tailwind-merge@3.4.0:
+ resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
+
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
hasBin: true
@@ -3847,28 +3853,28 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.53.5':
optional: true
- '@storybook/addon-designs@11.1.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
+ '@storybook/addon-designs@11.1.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
dependencies:
'@figspec/react': 2.0.1(@types/react@19.2.7)(react@19.2.3)
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
optionalDependencies:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
transitivePeerDependencies:
- '@types/react'
- '@storybook/addon-links@10.1.10(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
+ '@storybook/addon-links@10.2.0(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
dependencies:
'@storybook/global': 5.0.0
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
optionalDependencies:
react: 19.2.3
- '@storybook/builder-vite@10.1.10(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
+ '@storybook/builder-vite@10.2.0(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
dependencies:
- '@storybook/csf-plugin': 10.1.10(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
+ '@storybook/csf-plugin': 10.2.0(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
'@vitest/mocker': 3.2.4(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
ts-dedent: 2.2.0
vite: 7.3.0(jiti@2.6.1)(lightningcss@1.30.2)
transitivePeerDependencies:
@@ -3877,9 +3883,9 @@ snapshots:
- rollup
- webpack
- '@storybook/csf-plugin@10.1.10(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
+ '@storybook/csf-plugin@10.2.0(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
dependencies:
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
unplugin: 2.3.11
optionalDependencies:
esbuild: 0.27.2
@@ -3893,25 +3899,25 @@ snapshots:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
- '@storybook/react-dom-shim@10.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
+ '@storybook/react-dom-shim@10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))':
dependencies:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@storybook/react-vite@10.1.10(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
+ '@storybook/react-vite@10.2.0(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))':
dependencies:
'@joshwooding/vite-plugin-react-docgen-typescript': 0.6.3(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
'@rollup/pluginutils': 5.3.0(rollup@4.53.5)
- '@storybook/builder-vite': 10.1.10(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
- '@storybook/react': 10.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
+ '@storybook/builder-vite': 10.2.0(esbuild@0.27.2)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
+ '@storybook/react': 10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
empathic: 2.0.0
magic-string: 0.30.21
react: 19.2.3
react-docgen: 8.0.2
react-dom: 19.2.3(react@19.2.3)
resolve: 1.22.11
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
tsconfig-paths: 4.2.0
vite: 7.3.0(jiti@2.6.1)(lightningcss@1.30.2)
transitivePeerDependencies:
@@ -3922,14 +3928,14 @@ snapshots:
- typescript
- webpack
- '@storybook/react@10.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)':
+ '@storybook/react@10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)':
dependencies:
'@storybook/global': 5.0.0
- '@storybook/react-dom-shim': 10.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
+ '@storybook/react-dom-shim': 10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
react: 19.2.3
react-docgen: 8.0.2
react-dom: 19.2.3(react@19.2.3)
- storybook: 10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
@@ -5618,7 +5624,7 @@ snapshots:
es-errors: 1.3.0
internal-slot: 1.1.0
- storybook@10.1.10(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
+ storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
'@storybook/global': 5.0.0
'@storybook/icons': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5729,6 +5735,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ tailwind-merge@3.4.0: {}
+
tailwindcss@4.1.18: {}
tapable@2.3.0: {}
diff --git a/src/components/DropdownMenu/DropdownMenu.stories.tsx b/src/components/DropdownMenu/DropdownMenu.stories.tsx
index 1f4f81f..069621b 100644
--- a/src/components/DropdownMenu/DropdownMenu.stories.tsx
+++ b/src/components/DropdownMenu/DropdownMenu.stories.tsx
@@ -36,7 +36,7 @@ export const SelectModel: Story = {
- A
+ A
}
checked
@@ -47,7 +47,7 @@ export const SelectModel: Story = {
variant="active"
avatar={
- A
+ A
}
>
@@ -56,7 +56,7 @@ export const SelectModel: Story = {
- G
+ G
}
secondaryIcon="plus"
@@ -66,7 +66,7 @@ export const SelectModel: Story = {
- G
+ G
}
secondaryIcon="plus"
@@ -76,7 +76,7 @@ export const SelectModel: Story = {
- O
+ O
}
secondaryIcon="plus"
@@ -86,7 +86,7 @@ export const SelectModel: Story = {
- O
+ O
}
secondaryIcon="plus"
@@ -96,7 +96,7 @@ export const SelectModel: Story = {
- O
+ O
}
secondaryIcon="plus"
@@ -106,7 +106,7 @@ export const SelectModel: Story = {
- O
+ O
}
secondaryIcon="plus"
@@ -151,7 +151,7 @@ export const AddTeamMember: Story = {
-
+
B
@@ -163,7 +163,7 @@ export const AddTeamMember: Story = {
- D
+ D
}
secondaryIcon="plus"
@@ -173,7 +173,7 @@ export const AddTeamMember: Story = {
- E
+ E
}
secondaryIcon="plus"
@@ -183,7 +183,7 @@ export const AddTeamMember: Story = {
- L
+ L
}
secondaryIcon="plus"
@@ -193,7 +193,7 @@ export const AddTeamMember: Story = {
- N
+ N
}
secondaryIcon="plus"
@@ -203,7 +203,7 @@ export const AddTeamMember: Story = {
- R
+ R
}
secondaryIcon="plus"
@@ -220,7 +220,7 @@ export const ViewParticipants: Story = {
- L
+ L
}
>
@@ -229,7 +229,7 @@ export const ViewParticipants: Story = {
- B
+ B
}
secondaryIcon="plus"
@@ -239,7 +239,7 @@ export const ViewParticipants: Story = {
- R
+ R
}
secondaryIcon="plus"
diff --git a/src/components/ModelUserManagement/ModelUserManagement.tsx b/src/components/ModelUserManagement/ModelUserManagement.tsx
index f53e777..d25e317 100644
--- a/src/components/ModelUserManagement/ModelUserManagement.tsx
+++ b/src/components/ModelUserManagement/ModelUserManagement.tsx
@@ -44,8 +44,7 @@ const ModelUserManagement = React.forwardRef<
});
ModelUserManagement.displayName = 'ModelUserManagement';
-export interface ModelSelectorProps
- extends React.ButtonHTMLAttributes {}
+export type ModelSelectorProps = React.ButtonHTMLAttributes;
const ModelSelector = React.forwardRef(
({ className, children, ...props }, ref) => {
@@ -80,8 +79,7 @@ const UserManagementGroup = React.forwardRef<
});
UserManagementGroup.displayName = 'UserManagementGroup';
-export interface AddUserButtonProps
- extends React.ButtonHTMLAttributes {}
+export type AddUserButtonProps = React.ButtonHTMLAttributes;
const AddUserButton = React.forwardRef(
({ className, ...props }, ref) => {
@@ -111,7 +109,7 @@ const UserAvatars = React.forwardRef(
(
);
UserAvatars.displayName = 'UserAvatars';
-export interface UserDropdownTriggerProps
- extends React.ButtonHTMLAttributes
{}
+export type UserDropdownTriggerProps = React.ButtonHTMLAttributes;
const UserDropdownTrigger = React.forwardRef<
HTMLButtonElement,
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 56c19b2..3de80f0 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,9 +1,11 @@
import { clsx, type ClassValue } from 'clsx';
+import { twMerge } from 'tailwind-merge';
/**
* Utility function to merge class names
- * Combines clsx for conditional classes
+ * Combines clsx for conditional classes with tailwind-merge
+ * to properly handle conflicting Tailwind classes
*/
export function cn(...inputs: ClassValue[]) {
- return clsx(inputs);
+ return twMerge(clsx(inputs));
}
From 2b305cbdf9d0b2cdf55334df4151837b00d7ef11 Mon Sep 17 00:00:00 2001
From: Rob Di Marco
Date: Fri, 23 Jan 2026 12:11:02 -0500
Subject: [PATCH 3/9] Storybook upgrade
---
.storybook/main.ts | 3 +-
.storybook/preview.ts | 23 ++++---
eslint.config.js | 64 +++++++++----------
package.json | 11 ++--
pnpm-lock.yaml | 29 +++++----
.../Accordion/Accordion.stories.tsx | 2 +-
src/components/Alert/Alert.stories.tsx | 2 +-
.../AlertDialog/AlertDialog.stories.tsx | 2 +-
src/components/Avatar/Avatar.stories.tsx | 2 +-
.../AvatarGroup/AvatarGroup.stories.tsx | 2 +-
src/components/Badge/Badge.stories.tsx | 2 +-
.../Breadcrumb/Breadcrumb.stories.tsx | 2 +-
src/components/Button/Button.stories.tsx | 2 +-
.../ButtonGroup/ButtonGroup.stories.tsx | 2 +-
src/components/Card/Card.stories.tsx | 2 +-
src/components/Carousel/Carousel.stories.tsx | 2 +-
src/components/Checkbox/Checkbox.stories.tsx | 2 +-
src/components/Dialog/Dialog.stories.tsx | 2 +-
src/components/Drawer/Drawer.stories.tsx | 2 +-
.../DropdownMenu/DropdownMenu.stories.tsx | 2 +-
src/components/Header/Header.stories.tsx | 2 +-
.../HoverCard/HoverCard.stories.tsx | 2 +-
src/components/Icon/Icon.stories.tsx | 2 +-
.../Indicators/Indicators.stories.tsx | 2 +-
src/components/Input/Input.stories.tsx | 2 +-
.../InputGroup/InputGroup.stories.tsx | 2 +-
src/components/Label/Label.stories.tsx | 2 +-
src/components/Menubar/Menubar.stories.tsx | 2 +-
.../ModelUserManagement.stories.tsx | 2 +-
.../NavHeader/NavHeader.stories.tsx | 2 +-
.../NavSidePanel/NavSidePanel.stories.tsx | 2 +-
.../Pagination/Pagination.stories.tsx | 2 +-
src/components/Popover/Popover.stories.tsx | 2 +-
src/components/Progress/Progress.stories.tsx | 2 +-
src/components/Radio/Radio.stories.tsx | 2 +-
.../Scrollbar/Scrollbar.stories.tsx | 2 +-
src/components/Select/Select.stories.tsx | 2 +-
.../Separator/Separator.stories.tsx | 2 +-
src/components/Sheet/Sheet.stories.tsx | 2 +-
src/components/Skeleton/Skeleton.stories.tsx | 2 +-
src/components/Slider/Slider.stories.tsx | 2 +-
src/components/Switch/Switch.stories.tsx | 2 +-
src/components/Table/Table.stories.tsx | 2 +-
src/components/Tabs/Tabs.stories.tsx | 2 +-
src/components/Textarea/Textarea.stories.tsx | 2 +-
src/components/Theme/Theme.stories.tsx | 2 +-
src/components/Toast/Toast.stories.tsx | 2 +-
src/components/Toggle/Toggle.stories.tsx | 2 +-
src/components/Tooltip/Tooltip.stories.tsx | 2 +-
49 files changed, 116 insertions(+), 102 deletions(-)
diff --git a/.storybook/main.ts b/.storybook/main.ts
index b06b47f..f930b89 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -1,6 +1,7 @@
+// This file has been automatically migrated to valid ESM format by Storybook.
import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';
-import path from 'path';
+import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
diff --git a/.storybook/preview.ts b/.storybook/preview.ts
index d53b231..7096dd3 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.ts
@@ -1,4 +1,4 @@
-import type { Preview } from '@storybook/react';
+import type { Preview } from '@storybook/react-vite';
import '../src/styles/globals.css';
const preview: Preview = {
@@ -10,23 +10,30 @@ const preview: Preview = {
},
},
backgrounds: {
- default: 'light',
- values: [
- {
+ options: {
+ light: {
name: 'light',
value: '#ffffff',
},
- {
+
+ dark: {
name: 'dark',
value: '#020618',
},
- {
+
+ muted: {
name: 'muted',
value: '#f1f5f9',
- },
- ],
+ }
+ }
},
},
+
+ initialGlobals: {
+ backgrounds: {
+ value: 'light'
+ }
+ }
};
export default preview;
diff --git a/eslint.config.js b/eslint.config.js
index ff5b323..75362de 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,3 +1,6 @@
+// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
+import storybook from "eslint-plugin-storybook";
+
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
@@ -5,40 +8,37 @@ import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import globals from 'globals';
-export default [
- js.configs.recommended,
- {
- files: ['**/*.{ts,tsx}'],
- languageOptions: {
- parser: typescriptParser,
- parserOptions: {
- ecmaVersion: 'latest',
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
- },
- },
- globals: {
- ...globals.browser,
- ...globals.es2021,
+export default [js.configs.recommended, {
+ files: ['**/*.{ts,tsx}'],
+ languageOptions: {
+ parser: typescriptParser,
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
},
},
- plugins: {
- '@typescript-eslint': typescript,
- 'react': react,
- 'react-hooks': reactHooks,
+ globals: {
+ ...globals.browser,
+ ...globals.es2021,
},
- rules: {
- ...typescript.configs.recommended.rules,
- ...react.configs.recommended.rules,
- ...reactHooks.configs.recommended.rules,
- 'react/react-in-jsx-scope': 'off',
- 'react/prop-types': 'off',
- },
- settings: {
- react: {
- version: 'detect',
- },
+ },
+ plugins: {
+ '@typescript-eslint': typescript,
+ 'react': react,
+ 'react-hooks': reactHooks,
+ },
+ rules: {
+ ...typescript.configs.recommended.rules,
+ ...react.configs.recommended.rules,
+ ...reactHooks.configs.recommended.rules,
+ 'react/react-in-jsx-scope': 'off',
+ 'react/prop-types': 'off',
+ },
+ settings: {
+ react: {
+ version: 'detect',
},
},
-];
+}, ...storybook.configs["flat/recommended"]];
diff --git a/package.json b/package.json
index 4c48ce0..d0b77f0 100644
--- a/package.json
+++ b/package.json
@@ -49,16 +49,15 @@
"homepage": "https://github.com/atxp-dev/design-system#readme",
"sideEffects": false,
"peerDependencies": {
- "lucide-react": "^0.562.0",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0",
+ "lucide-react": "^0.562.0",
"sonner": "^2.0.7"
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@storybook/addon-designs": "^11.1.1",
"@storybook/addon-links": "^10.2.0",
- "@storybook/react": "^10.2.0",
"@storybook/react-vite": "^10.2.0",
"@tailwindcss/cli": "^4.1.18",
"@tailwindcss/postcss": "^4.1.18",
@@ -79,7 +78,8 @@
"tailwindcss": "^4.1.18",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
- "vite": "^7.3.0"
+ "vite": "^7.3.0",
+ "eslint-plugin-storybook": "10.2.0"
},
"dependencies": {
"@radix-ui/react-accordion": "^1.2.12",
@@ -90,8 +90,7 @@
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "tailwind-merge": "^3.4.0"
+ "clsx": "^2.1.1"
},
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
-}
+}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a8f5509..06c6154 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,9 +41,6 @@ importers:
sonner:
specifier: ^2.0.7
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- tailwind-merge:
- specifier: ^3.4.0
- version: 3.4.0
devDependencies:
'@eslint/js':
specifier: ^9.39.2
@@ -54,9 +51,6 @@ importers:
'@storybook/addon-links':
specifier: ^10.2.0
version: 10.2.0(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))
- '@storybook/react':
- specifier: ^10.2.0
- version: 10.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
'@storybook/react-vite':
specifier: ^10.2.0
version: 10.2.0(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.5)(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.0(jiti@2.6.1)(lightningcss@1.30.2))
@@ -93,6 +87,9 @@ importers:
eslint-plugin-react-hooks:
specifier: ^7.0.1
version: 7.0.1(eslint@9.39.2(jiti@2.6.1))
+ eslint-plugin-storybook:
+ specifier: 10.2.0
+ version: 10.2.0(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
globals:
specifier: ^16.5.0
version: 16.5.0
@@ -1780,6 +1777,12 @@ packages:
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+ eslint-plugin-storybook@10.2.0:
+ resolution: {integrity: sha512-OtQJ153FOusr8bIMzccjkfMFJEex/3NFx0iXZ+UaeQ0WXearQ+37EGgBay3onkFElyu8AySggq/fdTknPAEvPA==}
+ peerDependencies:
+ eslint: '>=8'
+ storybook: ^10.2.0
+
eslint-scope@8.4.0:
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2758,9 +2761,6 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- tailwind-merge@3.4.0:
- resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
-
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
hasBin: true
@@ -4703,6 +4703,15 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
+ eslint-plugin-storybook@10.2.0(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3):
+ dependencies:
+ '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
+ eslint: 9.39.2(jiti@2.6.1)
+ storybook: 10.2.0(@testing-library/dom@10.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
eslint-scope@8.4.0:
dependencies:
esrecurse: 4.3.0
@@ -5735,8 +5744,6 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
- tailwind-merge@3.4.0: {}
-
tailwindcss@4.1.18: {}
tapable@2.3.0: {}
diff --git a/src/components/Accordion/Accordion.stories.tsx b/src/components/Accordion/Accordion.stories.tsx
index 0a8c867..b0ed071 100644
--- a/src/components/Accordion/Accordion.stories.tsx
+++ b/src/components/Accordion/Accordion.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Accordion,
AccordionContent,
diff --git a/src/components/Alert/Alert.stories.tsx b/src/components/Alert/Alert.stories.tsx
index 42fc6cb..145d72b 100644
--- a/src/components/Alert/Alert.stories.tsx
+++ b/src/components/Alert/Alert.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Alert, AlertDescription, AlertTitle } from './Alert';
import { Icon, AlertCircle } from '@/components/Icon';
diff --git a/src/components/AlertDialog/AlertDialog.stories.tsx b/src/components/AlertDialog/AlertDialog.stories.tsx
index 3665776..0c0f311 100644
--- a/src/components/AlertDialog/AlertDialog.stories.tsx
+++ b/src/components/AlertDialog/AlertDialog.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { useState } from 'react';
import {
AlertDialog,
diff --git a/src/components/Avatar/Avatar.stories.tsx b/src/components/Avatar/Avatar.stories.tsx
index 8a6bc60..8d62136 100644
--- a/src/components/Avatar/Avatar.stories.tsx
+++ b/src/components/Avatar/Avatar.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Avatar, AvatarFallback, AvatarImage } from './Avatar';
/**
diff --git a/src/components/AvatarGroup/AvatarGroup.stories.tsx b/src/components/AvatarGroup/AvatarGroup.stories.tsx
index 37b70d4..04da1d0 100644
--- a/src/components/AvatarGroup/AvatarGroup.stories.tsx
+++ b/src/components/AvatarGroup/AvatarGroup.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { AvatarGroup, AvatarGroupItem } from './AvatarGroup';
const meta = {
diff --git a/src/components/Badge/Badge.stories.tsx b/src/components/Badge/Badge.stories.tsx
index 81a970d..aee58b5 100644
--- a/src/components/Badge/Badge.stories.tsx
+++ b/src/components/Badge/Badge.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Badge } from './Badge';
/**
diff --git a/src/components/Breadcrumb/Breadcrumb.stories.tsx b/src/components/Breadcrumb/Breadcrumb.stories.tsx
index a378ebc..6e37bde 100644
--- a/src/components/Breadcrumb/Breadcrumb.stories.tsx
+++ b/src/components/Breadcrumb/Breadcrumb.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Breadcrumb,
BreadcrumbList,
diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx
index aba2383..03426e9 100644
--- a/src/components/Button/Button.stories.tsx
+++ b/src/components/Button/Button.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Button } from './Button';
import { Icon, Plus } from '@/components/Icon';
diff --git a/src/components/ButtonGroup/ButtonGroup.stories.tsx b/src/components/ButtonGroup/ButtonGroup.stories.tsx
index 59e6c2d..a9d9c86 100644
--- a/src/components/ButtonGroup/ButtonGroup.stories.tsx
+++ b/src/components/ButtonGroup/ButtonGroup.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { ButtonGroup } from './ButtonGroup';
import { Button } from '@/components/Button';
import { Icon, Plus, ChevronDown, ExternalLink, Phone } from '@/components/Icon';
diff --git a/src/components/Card/Card.stories.tsx b/src/components/Card/Card.stories.tsx
index 9ff8139..eec68ca 100644
--- a/src/components/Card/Card.stories.tsx
+++ b/src/components/Card/Card.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Card,
CardContent,
diff --git a/src/components/Carousel/Carousel.stories.tsx b/src/components/Carousel/Carousel.stories.tsx
index cb36c96..a02f605 100644
--- a/src/components/Carousel/Carousel.stories.tsx
+++ b/src/components/Carousel/Carousel.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Carousel,
CarouselContent,
diff --git a/src/components/Checkbox/Checkbox.stories.tsx b/src/components/Checkbox/Checkbox.stories.tsx
index 1569c0f..2ef80a7 100644
--- a/src/components/Checkbox/Checkbox.stories.tsx
+++ b/src/components/Checkbox/Checkbox.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Checkbox } from './Checkbox';
/**
diff --git a/src/components/Dialog/Dialog.stories.tsx b/src/components/Dialog/Dialog.stories.tsx
index e18c5d3..4b7dff9 100644
--- a/src/components/Dialog/Dialog.stories.tsx
+++ b/src/components/Dialog/Dialog.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { useState } from 'react';
import {
Dialog,
diff --git a/src/components/Drawer/Drawer.stories.tsx b/src/components/Drawer/Drawer.stories.tsx
index 3fd9897..663e0d5 100644
--- a/src/components/Drawer/Drawer.stories.tsx
+++ b/src/components/Drawer/Drawer.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { useState } from 'react';
import {
Drawer,
diff --git a/src/components/DropdownMenu/DropdownMenu.stories.tsx b/src/components/DropdownMenu/DropdownMenu.stories.tsx
index 069621b..b4c6624 100644
--- a/src/components/DropdownMenu/DropdownMenu.stories.tsx
+++ b/src/components/DropdownMenu/DropdownMenu.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { DropdownMenu, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator } from './DropdownMenu';
import { Avatar, AvatarFallback } from '@/components/Avatar';
import { Input } from '@/components/Input';
diff --git a/src/components/Header/Header.stories.tsx b/src/components/Header/Header.stories.tsx
index cdba040..4eb5f21 100644
--- a/src/components/Header/Header.stories.tsx
+++ b/src/components/Header/Header.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Header,
HeaderBreadcrumbs,
diff --git a/src/components/HoverCard/HoverCard.stories.tsx b/src/components/HoverCard/HoverCard.stories.tsx
index 6eae3fe..9817f7a 100644
--- a/src/components/HoverCard/HoverCard.stories.tsx
+++ b/src/components/HoverCard/HoverCard.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
HoverCard,
HoverCardHeader,
diff --git a/src/components/Icon/Icon.stories.tsx b/src/components/Icon/Icon.stories.tsx
index b3976b1..ac28e26 100644
--- a/src/components/Icon/Icon.stories.tsx
+++ b/src/components/Icon/Icon.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Icon } from './Icon';
import * as Icons from 'lucide-react';
diff --git a/src/components/Indicators/Indicators.stories.tsx b/src/components/Indicators/Indicators.stories.tsx
index 74802e9..ca63f16 100644
--- a/src/components/Indicators/Indicators.stories.tsx
+++ b/src/components/Indicators/Indicators.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { IndicatorDot, IndicatorCircle } from './Indicators';
/**
diff --git a/src/components/Input/Input.stories.tsx b/src/components/Input/Input.stories.tsx
index 8b2e8d3..1f1f20c 100644
--- a/src/components/Input/Input.stories.tsx
+++ b/src/components/Input/Input.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Input } from './Input';
import { Icon, Search } from '@/components/Icon';
diff --git a/src/components/InputGroup/InputGroup.stories.tsx b/src/components/InputGroup/InputGroup.stories.tsx
index d669ce1..de61b41 100644
--- a/src/components/InputGroup/InputGroup.stories.tsx
+++ b/src/components/InputGroup/InputGroup.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { InputGroup, InputGroupLabel, InputGroupHelpText } from './InputGroup';
import { Input } from '@/components/Input';
diff --git a/src/components/Label/Label.stories.tsx b/src/components/Label/Label.stories.tsx
index 692a845..201bb81 100644
--- a/src/components/Label/Label.stories.tsx
+++ b/src/components/Label/Label.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Label } from './Label';
/**
diff --git a/src/components/Menubar/Menubar.stories.tsx b/src/components/Menubar/Menubar.stories.tsx
index be9e5ef..30d66af 100644
--- a/src/components/Menubar/Menubar.stories.tsx
+++ b/src/components/Menubar/Menubar.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
Menubar,
MenubarTrigger,
diff --git a/src/components/ModelUserManagement/ModelUserManagement.stories.tsx b/src/components/ModelUserManagement/ModelUserManagement.stories.tsx
index 4b3259d..fa889e6 100644
--- a/src/components/ModelUserManagement/ModelUserManagement.stories.tsx
+++ b/src/components/ModelUserManagement/ModelUserManagement.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
ModelUserManagement,
ModelSelector,
diff --git a/src/components/NavHeader/NavHeader.stories.tsx b/src/components/NavHeader/NavHeader.stories.tsx
index 7fc06f1..68f2aed 100644
--- a/src/components/NavHeader/NavHeader.stories.tsx
+++ b/src/components/NavHeader/NavHeader.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
NavHeader,
NavHeaderBrand,
diff --git a/src/components/NavSidePanel/NavSidePanel.stories.tsx b/src/components/NavSidePanel/NavSidePanel.stories.tsx
index 021dbd9..1685b3b 100644
--- a/src/components/NavSidePanel/NavSidePanel.stories.tsx
+++ b/src/components/NavSidePanel/NavSidePanel.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
NavSidePanel,
NavSidePanelHeader,
diff --git a/src/components/Pagination/Pagination.stories.tsx b/src/components/Pagination/Pagination.stories.tsx
index 38cfaa8..480dfd9 100644
--- a/src/components/Pagination/Pagination.stories.tsx
+++ b/src/components/Pagination/Pagination.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
Pagination,
PaginationItem,
diff --git a/src/components/Popover/Popover.stories.tsx b/src/components/Popover/Popover.stories.tsx
index 12bc3ca..115a7e7 100644
--- a/src/components/Popover/Popover.stories.tsx
+++ b/src/components/Popover/Popover.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
Popover,
PopoverHeader,
diff --git a/src/components/Progress/Progress.stories.tsx b/src/components/Progress/Progress.stories.tsx
index 0b7f0ca..92cef75 100644
--- a/src/components/Progress/Progress.stories.tsx
+++ b/src/components/Progress/Progress.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Progress } from './Progress';
import { useState, useEffect } from 'react';
diff --git a/src/components/Radio/Radio.stories.tsx b/src/components/Radio/Radio.stories.tsx
index f45dffe..5afd249 100644
--- a/src/components/Radio/Radio.stories.tsx
+++ b/src/components/Radio/Radio.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Radio } from './Radio';
/**
diff --git a/src/components/Scrollbar/Scrollbar.stories.tsx b/src/components/Scrollbar/Scrollbar.stories.tsx
index 10b27a4..68f4640 100644
--- a/src/components/Scrollbar/Scrollbar.stories.tsx
+++ b/src/components/Scrollbar/Scrollbar.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
const meta = {
title: 'Design System/Scrollbar',
diff --git a/src/components/Select/Select.stories.tsx b/src/components/Select/Select.stories.tsx
index 7f934f3..463ce44 100644
--- a/src/components/Select/Select.stories.tsx
+++ b/src/components/Select/Select.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import {
Select,
SelectContent,
diff --git a/src/components/Separator/Separator.stories.tsx b/src/components/Separator/Separator.stories.tsx
index f4fed3d..8cc3968 100644
--- a/src/components/Separator/Separator.stories.tsx
+++ b/src/components/Separator/Separator.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Separator } from './Separator';
/**
diff --git a/src/components/Sheet/Sheet.stories.tsx b/src/components/Sheet/Sheet.stories.tsx
index 56ea78d..c3a6478 100644
--- a/src/components/Sheet/Sheet.stories.tsx
+++ b/src/components/Sheet/Sheet.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { useState } from 'react';
import {
Sheet,
diff --git a/src/components/Skeleton/Skeleton.stories.tsx b/src/components/Skeleton/Skeleton.stories.tsx
index a82cce8..2fd3802 100644
--- a/src/components/Skeleton/Skeleton.stories.tsx
+++ b/src/components/Skeleton/Skeleton.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Skeleton } from './Skeleton';
/**
diff --git a/src/components/Slider/Slider.stories.tsx b/src/components/Slider/Slider.stories.tsx
index 85f09b4..a49e44a 100644
--- a/src/components/Slider/Slider.stories.tsx
+++ b/src/components/Slider/Slider.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import * as React from 'react';
import { Slider } from './Slider';
diff --git a/src/components/Switch/Switch.stories.tsx b/src/components/Switch/Switch.stories.tsx
index 64395b3..efb6daf 100644
--- a/src/components/Switch/Switch.stories.tsx
+++ b/src/components/Switch/Switch.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import * as React from 'react';
import { Switch } from './Switch';
diff --git a/src/components/Table/Table.stories.tsx b/src/components/Table/Table.stories.tsx
index efe0a78..90bc29c 100644
--- a/src/components/Table/Table.stories.tsx
+++ b/src/components/Table/Table.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import {
Table,
TableBody,
diff --git a/src/components/Tabs/Tabs.stories.tsx b/src/components/Tabs/Tabs.stories.tsx
index c7f84ff..62f1907 100644
--- a/src/components/Tabs/Tabs.stories.tsx
+++ b/src/components/Tabs/Tabs.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Tabs, TabsList, TabsTrigger, TabsContent } from './Tabs';
/**
diff --git a/src/components/Textarea/Textarea.stories.tsx b/src/components/Textarea/Textarea.stories.tsx
index 7fc45d3..65c21df 100644
--- a/src/components/Textarea/Textarea.stories.tsx
+++ b/src/components/Textarea/Textarea.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import * as React from 'react';
import { Textarea } from './Textarea';
diff --git a/src/components/Theme/Theme.stories.tsx b/src/components/Theme/Theme.stories.tsx
index 2bf187a..1e5c770 100644
--- a/src/components/Theme/Theme.stories.tsx
+++ b/src/components/Theme/Theme.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { ThemeProvider, useTheme, Theme } from '@/lib/theme';
import { Button } from '@/components/Button';
import { Card } from '@/components/Card';
diff --git a/src/components/Toast/Toast.stories.tsx b/src/components/Toast/Toast.stories.tsx
index 0274045..c2100d8 100644
--- a/src/components/Toast/Toast.stories.tsx
+++ b/src/components/Toast/Toast.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta } from '@storybook/react';
+import type { Meta } from '@storybook/react-vite';
import { Toaster, toast } from './Toast';
import { Button } from '../Button';
diff --git a/src/components/Toggle/Toggle.stories.tsx b/src/components/Toggle/Toggle.stories.tsx
index ab40ff2..621e8ab 100644
--- a/src/components/Toggle/Toggle.stories.tsx
+++ b/src/components/Toggle/Toggle.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import * as React from 'react';
import { Toggle } from './Toggle';
import { Bold, Italic, Underline, Type } from 'lucide-react';
diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx
index 915fe41..bd32b9a 100644
--- a/src/components/Tooltip/Tooltip.stories.tsx
+++ b/src/components/Tooltip/Tooltip.stories.tsx
@@ -1,4 +1,4 @@
-import type { Meta, StoryObj } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react-vite';
import { Tooltip } from './Tooltip';
const meta = {
From eff72f2681a6ff3dab75acd3de3bcc4eb96a78d8 Mon Sep 17 00:00:00 2001
From: Rob Di Marco
Date: Fri, 23 Jan 2026 12:11:58 -0500
Subject: [PATCH 4/9] Add tailwind-merge dependency to package.json
This dependency is required for the cn utility function to properly
merge conflicting Tailwind classes. Without it, component size overrides
don't work correctly (e.g., h-4 w-4 on Avatar doesn't override h-10 w-10).
The previous pnpm add command updated node_modules but didn't save
to package.json properly.
---
package.json | 9 +++++----
pnpm-lock.yaml | 8 ++++++++
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/package.json b/package.json
index d0b77f0..8acaec6 100644
--- a/package.json
+++ b/package.json
@@ -49,9 +49,9 @@
"homepage": "https://github.com/atxp-dev/design-system#readme",
"sideEffects": false,
"peerDependencies": {
+ "lucide-react": "^0.562.0",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0",
- "lucide-react": "^0.562.0",
"sonner": "^2.0.7"
},
"devDependencies": {
@@ -70,6 +70,7 @@
"eslint": "^9.39.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
+ "eslint-plugin-storybook": "10.2.0",
"globals": "^16.5.0",
"postcss": "^8.5.6",
"react": "^19.2.3",
@@ -78,8 +79,7 @@
"tailwindcss": "^4.1.18",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
- "vite": "^7.3.0",
- "eslint-plugin-storybook": "10.2.0"
+ "vite": "^7.3.0"
},
"dependencies": {
"@radix-ui/react-accordion": "^1.2.12",
@@ -90,7 +90,8 @@
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1"
+ "clsx": "^2.1.1",
+ "tailwind-merge": "^3.4.0"
},
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 06c6154..be4ec33 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -41,6 +41,9 @@ importers:
sonner:
specifier: ^2.0.7
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ tailwind-merge:
+ specifier: ^3.4.0
+ version: 3.4.0
devDependencies:
'@eslint/js':
specifier: ^9.39.2
@@ -2761,6 +2764,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ tailwind-merge@3.4.0:
+ resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
+
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
hasBin: true
@@ -5744,6 +5750,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ tailwind-merge@3.4.0: {}
+
tailwindcss@4.1.18: {}
tapable@2.3.0: {}
From 66730449e043d30bb78be07efce437ed543d1142 Mon Sep 17 00:00:00 2001
From: Rob Di Marco
Date: Fri, 23 Jan 2026 12:13:41 -0500
Subject: [PATCH 5/9] Add border to UserAvatars container for visibility
The bg-background container was invisible on light backgrounds.
Added border-input to match Figma design and provide visual separation.
Also updated vanilla HTML examples to include the border.
---
src/components/ModelUserManagement/ModelUserManagement.tsx | 2 +-
vanilla/components/user-management.html | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/ModelUserManagement/ModelUserManagement.tsx b/src/components/ModelUserManagement/ModelUserManagement.tsx
index d25e317..6de30a8 100644
--- a/src/components/ModelUserManagement/ModelUserManagement.tsx
+++ b/src/components/ModelUserManagement/ModelUserManagement.tsx
@@ -109,7 +109,7 @@ const UserAvatars = React.forwardRef(
Model & User Management
-