color picker update

This commit is contained in:
Nate Kelley 2025-04-11 22:06:57 -06:00
parent 5d58091e0e
commit e2921f251e
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
5 changed files with 140 additions and 36 deletions

View File

@ -330,3 +330,35 @@ export const ManyValuesWithDataLabels: Story = {
pieDonutWidth: 0
}
};
export const DataLabelsOutside: Story = {
args: {
selectedChartType: ChartType.Pie,
data: Array.from({ length: 5 }, () => ({
segment: faker.word.adjective(),
value: faker.number.int({ min: 10, max: 100 })
})),
pieChartAxis: {
x: ['segment'],
y: ['value']
},
columnLabelFormats: {
segment: {
columnType: 'text',
style: 'string'
} satisfies IColumnLabelFormat,
value: {
columnType: 'number',
style: 'number',
numberSeparatorStyle: ','
} satisfies IColumnLabelFormat,
value2: {
columnType: 'number',
style: 'number',
numberSeparatorStyle: ','
} satisfies IColumnLabelFormat
} satisfies Record<keyof PieChartData, IColumnLabelFormat>,
pieLabelPosition: 'outside'
}
};

View File

@ -0,0 +1,90 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ColorPicker } from './ColorPicker';
const meta: Meta<typeof ColorPicker> = {
title: 'UI/ColorPicker/ColorPicker',
component: ColorPicker,
tags: ['autodocs'],
args: {
value: '#000000',
size: 'default',
variant: 'default'
},
argTypes: {
value: {
control: 'color',
description: 'The color value in hex format'
},
onChange: {
description: 'Callback function when color changes'
},
onChangeComplete: {
description: 'Callback function when color selection is complete'
},
size: {
control: 'select',
options: ['small', 'default', 'tall'],
description: 'The size of the color picker button'
},
variant: {
control: 'select',
options: ['default', 'outline', 'secondary', 'ghost', 'link'],
description: 'The variant style of the color picker button'
},
className: {
control: 'text',
description: 'Additional CSS classes to apply'
}
}
};
export default meta;
type Story = StoryObj<typeof ColorPicker>;
export const Default: Story = {
args: {
value: '#FF0000'
}
};
export const Small: Story = {
args: {
value: '#00FF00',
size: 'small'
}
};
export const Tall: Story = {
args: {
value: '#0000FF',
size: 'tall'
}
};
export const OutlineVariant: Story = {
args: {
value: '#800080',
variant: 'outline'
}
};
export const SecondaryVariant: Story = {
args: {
value: '#FFA500',
variant: 'secondary'
}
};
export const GhostVariant: Story = {
args: {
value: '#008080',
variant: 'ghost'
}
};
export const LinkVariant: Story = {
args: {
value: '#4B0082',
variant: 'link'
}
};

View File

@ -3,7 +3,8 @@ import { PopoverRoot, PopoverContent, PopoverTrigger } from '@/components/ui/pop
import { cva } from 'class-variance-authority';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/buttons';
import { ChromePicker } from 'react-color';
import { ChromePicker, ColorResult } from 'react-color';
import { useMemoizedFn } from '@/hooks';
const colorPickerVariants = cva(
'rounded border bg-background transition-colors hover:bg-item-hover hover:text-text-default',
@ -17,9 +18,9 @@ const colorPickerVariants = cva(
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-6 min-h-6 max-h-6 px-4',
tall: 'h-7 min-h-7 max-h-7 px-4',
small: 'h-5 min-h-5 max-h-5 px-3 text-xs'
default: 'h-6 min-h-6 max-h-6 px-1',
tall: 'h-7 min-h-7 max-h-7 px-0.5',
small: 'h-5 min-h-5 max-h-5 px-0.5 text-xs'
}
},
defaultVariants: {
@ -50,13 +51,17 @@ const ColorPicker = React.forwardRef<HTMLButtonElement, ColorPickerProps>(
},
ref
) => {
const handleChange = (color: any) => {
onChange?.(color.hex);
};
const handleChange = useMemoizedFn(
(color: ColorResult, event: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(color.hex);
}
);
const handleChangeComplete = (color: any) => {
onChangeComplete?.(color.hex);
};
const handleChangeComplete = useMemoizedFn(
(color: ColorResult, event: React.ChangeEvent<HTMLInputElement>) => {
onChangeComplete?.(color.hex);
}
);
return (
<PopoverRoot>

View File

@ -2,32 +2,9 @@ import type { Meta, StoryObj } from '@storybook/react';
import { AppSegmented } from './AppSegmented';
import { BottleChampagne, Grid, HouseModern, PaintRoller } from '../icons';
import { PreventNavigation } from '../layouts/PreventNavigation';
import { useRouter } from 'next/navigation';
import { usePathname, useSearchParams } from 'next/navigation';
import { useState } from 'react';
import { Checkbox } from '../checkbox';
// Mock the Next.js router
const MockNextRouter = ({ children }: { children: React.ReactNode }) => {
const mockRouter = {
back: () => {},
forward: () => {},
push: () => {},
replace: () => {},
refresh: () => {},
prefetch: () => Promise.resolve()
};
// @ts-ignore - we're mocking the router
useRouter.mockImplementation(() => mockRouter);
// @ts-ignore - we're mocking the pathname
usePathname.mockImplementation(() => '/');
// @ts-ignore - we're mocking the search params
useSearchParams.mockImplementation(() => new URLSearchParams());
return <>{children}</>;
};
const meta: Meta<typeof AppSegmented> = {
title: 'UI/Segmented/AppSegmented',
component: AppSegmented,
@ -37,9 +14,9 @@ const meta: Meta<typeof AppSegmented> = {
tags: ['autodocs'],
decorators: [
(Story) => (
<MockNextRouter>
<>
<Story />
</MockNextRouter>
</>
)
],
argTypes: {

View File

@ -13,7 +13,7 @@ const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
export const selectVariants = cva(
'flex w-full gap-x-1.5 transition-colors transition-border text-foreground duration-200 items-center justify-between rounded border px-3 py-1 text-sm focus:outline-none cursor-pointer disabled:cursor-not-allowed disabled:opacity-60 [&>span]:line-clamp-1',
'flex w-full gap-x-1.5 transition-colors transition-border text-foreground duration-200 items-center justify-between rounded border px-3 py-1 text-sm focus:outline-none cursor-pointer disabled:cursor-not-allowed disabled:opacity-60 [&>span]:line-clamp-1 ',
{
variants: {
variant: {