mirror of https://github.com/buster-so/buster.git
color picker updates
This commit is contained in:
parent
e2921f251e
commit
52f7d99c44
|
@ -73,6 +73,7 @@
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
|
"react-colorful": "^5.6.1",
|
||||||
"react-data-grid": "7.0.0-beta.47",
|
"react-data-grid": "7.0.0-beta.47",
|
||||||
"react-day-picker": "8.10.1",
|
"react-day-picker": "8.10.1",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
@ -18523,6 +18524,16 @@
|
||||||
"react": "*"
|
"react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-colorful": {
|
||||||
|
"version": "5.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
||||||
|
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-confetti": {
|
"node_modules/react-confetti": {
|
||||||
"version": "6.4.0",
|
"version": "6.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz",
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
|
"react-colorful": "^5.6.1",
|
||||||
"react-data-grid": "7.0.0-beta.47",
|
"react-data-grid": "7.0.0-beta.47",
|
||||||
"react-day-picker": "8.10.1",
|
"react-day-picker": "8.10.1",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
|
|
@ -7,8 +7,7 @@ const meta: Meta<typeof ColorPicker> = {
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
args: {
|
args: {
|
||||||
value: '#000000',
|
value: '#000000',
|
||||||
size: 'default',
|
size: 'default'
|
||||||
variant: 'default'
|
|
||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
value: {
|
value: {
|
||||||
|
@ -26,11 +25,7 @@ const meta: Meta<typeof ColorPicker> = {
|
||||||
options: ['small', 'default', 'tall'],
|
options: ['small', 'default', 'tall'],
|
||||||
description: 'The size of the color picker button'
|
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: {
|
className: {
|
||||||
control: 'text',
|
control: 'text',
|
||||||
description: 'Additional CSS classes to apply'
|
description: 'Additional CSS classes to apply'
|
||||||
|
@ -60,31 +55,3 @@ export const Tall: Story = {
|
||||||
size: 'tall'
|
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'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,100 +1,104 @@
|
||||||
import React from 'react';
|
'use client';
|
||||||
import { PopoverRoot, PopoverContent, PopoverTrigger } from '@/components/ui/popover/PopoverBase';
|
|
||||||
import { cva } from 'class-variance-authority';
|
import { forwardRef, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { HexColorPicker } from 'react-colorful';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Button } from '@/components/ui/buttons';
|
import { Button, ButtonProps } from '@/components/ui/buttons';
|
||||||
import { ChromePicker, ColorResult } from 'react-color';
|
import { Popover, PopoverRoot, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||||
import { useMemoizedFn } from '@/hooks';
|
import { Input } from '@/components/ui/inputs';
|
||||||
|
import { useDebounceFn } from '@/hooks';
|
||||||
|
import { cva } from 'class-variance-authority';
|
||||||
|
|
||||||
const colorPickerVariants = cva(
|
interface ColorPickerProps {
|
||||||
'rounded border bg-background transition-colors hover:bg-item-hover hover:text-text-default',
|
value: string | null | undefined;
|
||||||
{
|
onChange?: (value: string) => void;
|
||||||
variants: {
|
onChangeComplete?: (value: string) => void;
|
||||||
variant: {
|
onBlur?: () => void;
|
||||||
default: 'border-input',
|
disabled?: boolean;
|
||||||
outline: 'border-input',
|
size?: 'default' | 'small' | 'tall';
|
||||||
secondary: 'border-secondary bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
name?: string;
|
||||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
||||||
link: 'text-primary underline-offset-4 hover:underline'
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
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: {
|
|
||||||
variant: 'default',
|
|
||||||
size: 'default'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export interface ColorPickerProps {
|
|
||||||
value?: string | null;
|
|
||||||
onChange?: (color: string) => void;
|
|
||||||
onChangeComplete?: (color: string) => void;
|
|
||||||
size?: 'small' | 'default' | 'tall';
|
|
||||||
variant?: 'default' | 'outline' | 'secondary' | 'ghost' | 'link';
|
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColorPicker = React.forwardRef<HTMLButtonElement, ColorPickerProps>(
|
const colorPickerWrapperVariants = cva('border p-1 rounded cursor-pointer shadow', {
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
default: 'w-6 min-w-6 max-w-6 h-6 min-h-6 max-h-6',
|
||||||
|
small: 'w-5 min-w-5 max-w-5 h-5 min-h-5 max-h-5',
|
||||||
|
tall: 'w-7 min-w-7 max-w-7 h-7 min-h-7 max-h-7'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
true: 'cursor-not-allowed opacity-60',
|
||||||
|
false: 'cursor-pointer'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ColorPicker = forwardRef<HTMLInputElement, ColorPickerProps>(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
className,
|
disabled,
|
||||||
value = '#000000',
|
|
||||||
onChange,
|
|
||||||
onChangeComplete,
|
onChangeComplete,
|
||||||
size = 'default',
|
size = 'default',
|
||||||
variant = 'default'
|
value: valueProp = '#000000',
|
||||||
|
onChange,
|
||||||
|
name,
|
||||||
|
className = '',
|
||||||
|
...props
|
||||||
},
|
},
|
||||||
ref
|
forwardedRef
|
||||||
) => {
|
) => {
|
||||||
const handleChange = useMemoizedFn(
|
const [open, setOpen] = useState(false);
|
||||||
(color: ColorResult, event: React.ChangeEvent<HTMLInputElement>) => {
|
const [value, setValue] = useState(valueProp);
|
||||||
onChange?.(color.hex);
|
|
||||||
}
|
const parsedValue = useMemo(() => {
|
||||||
|
return value || '#000000';
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const { run: debouncedOnChangeComplete } = useDebounceFn(
|
||||||
|
(value: string) => {
|
||||||
|
onChangeComplete?.(value);
|
||||||
|
},
|
||||||
|
{ wait: 150 }
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleChangeComplete = useMemoizedFn(
|
const handleInputChange = useCallback(
|
||||||
(color: ColorResult, event: React.ChangeEvent<HTMLInputElement>) => {
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
onChangeComplete?.(color.hex);
|
setValue(e?.currentTarget?.value);
|
||||||
}
|
onChange?.(e?.currentTarget?.value);
|
||||||
|
debouncedOnChangeComplete?.(e?.currentTarget?.value);
|
||||||
|
},
|
||||||
|
[onChange, debouncedOnChangeComplete]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleHexColorPickerChange = useCallback(
|
||||||
|
(color: string) => {
|
||||||
|
setValue(color);
|
||||||
|
onChange?.(color);
|
||||||
|
debouncedOnChangeComplete?.(color);
|
||||||
|
},
|
||||||
|
[onChange, debouncedOnChangeComplete]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<PopoverRoot>
|
<PopoverRoot onOpenChange={setOpen} open={open}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild disabled={disabled}>
|
||||||
<Button ref={ref} className={cn(colorPickerVariants({ size, variant }), className)}>
|
<div className={colorPickerWrapperVariants({ size, disabled })}>
|
||||||
<div
|
<div className="h-full w-full rounded-sm" style={{ backgroundColor: parsedValue }} />
|
||||||
className="border-border h-4 w-4 rounded-sm border"
|
</div>
|
||||||
style={{ backgroundColor: value || '#000000' }}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-auto p-0" align="start">
|
<PopoverContent className="w-full" align="end" side="bottom">
|
||||||
<ChromePicker
|
<HexColorPicker color={parsedValue} onChange={handleHexColorPickerChange} />
|
||||||
color={value || '#000000'}
|
<Input
|
||||||
onChange={handleChange}
|
className="mt-2.5"
|
||||||
onChangeComplete={handleChangeComplete}
|
maxLength={7}
|
||||||
disableAlpha
|
onChange={handleInputChange}
|
||||||
styles={{
|
value={parsedValue}
|
||||||
default: {
|
|
||||||
picker: {
|
|
||||||
background: 'var(--background)',
|
|
||||||
border: '1px solid var(--border)',
|
|
||||||
boxShadow: 'var(--shadow)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</PopoverRoot>
|
</PopoverRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
ColorPicker.displayName = 'ColorPicker';
|
ColorPicker.displayName = 'ColorPicker';
|
||||||
|
|
||||||
export { ColorPicker };
|
export { ColorPicker };
|
||||||
|
|
|
@ -185,7 +185,6 @@ const GoalLineItemContent: React.FC<{
|
||||||
<LabelAndInput label="Goal line color">
|
<LabelAndInput label="Goal line color">
|
||||||
<div className="flex w-full items-center justify-end">
|
<div className="flex w-full items-center justify-end">
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
size="small"
|
|
||||||
value={goalLineColor}
|
value={goalLineColor}
|
||||||
onChangeComplete={(color) => {
|
onChangeComplete={(color) => {
|
||||||
const hexColor = color;
|
const hexColor = color;
|
||||||
|
|
|
@ -11,8 +11,6 @@ export const ReasoningMessage_Text: React.FC<ReasoningMessageProps> = React.memo
|
||||||
(x) => (x?.reasoning_messages[reasoningMessageId] as BusterChatMessageReasoning_text)?.message
|
(x) => (x?.reasoning_messages[reasoningMessageId] as BusterChatMessageReasoning_text)?.message
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
console.log('message', message);
|
|
||||||
|
|
||||||
if (!message) return null;
|
if (!message) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue