feat: unify CardHeader padding across components
- Updated `CardHeader` padding from `pb-3` to `pb-4` in `JiraLogs`, `JiraSync`, `KanbanColumn`, `ObjectivesBoard`, and `DesktopControls` for consistent spacing. - Refactored `DesktopControls` and `KanbanFilters` to utilize new `ControlPanel`, `ControlSection`, and `ControlGroup` components, enhancing layout structure and maintainability. - Replaced button elements with `ToggleButton` and `FilterChip` components in various filter sections for improved UI consistency and usability.
This commit is contained in:
78
src/components/ui/SearchInput.tsx
Normal file
78
src/components/ui/SearchInput.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { InputHTMLAttributes, forwardRef, useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { Input } from './Input';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface SearchInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
onDebouncedChange?: (value: string) => void;
|
||||
debounceMs?: number;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
|
||||
({
|
||||
value = '',
|
||||
onChange,
|
||||
onDebouncedChange,
|
||||
debounceMs = 300,
|
||||
placeholder = "Rechercher...",
|
||||
className,
|
||||
...props
|
||||
}, ref) => {
|
||||
const [localValue, setLocalValue] = useState(value);
|
||||
const timeoutRef = useRef<number | undefined>(undefined);
|
||||
|
||||
// Fonction debouncée pour les changements
|
||||
const debouncedChange = useCallback((searchValue: string) => {
|
||||
if (timeoutRef.current) {
|
||||
window.clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
onDebouncedChange?.(searchValue);
|
||||
}, debounceMs);
|
||||
}, [onDebouncedChange, debounceMs]);
|
||||
|
||||
// Gérer les changements locaux
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value;
|
||||
setLocalValue(newValue);
|
||||
onChange?.(newValue);
|
||||
debouncedChange(newValue);
|
||||
};
|
||||
|
||||
// Synchroniser l'état local quand la valeur externe change
|
||||
useEffect(() => {
|
||||
setLocalValue(value);
|
||||
}, [value]);
|
||||
|
||||
// Nettoyer le timeout au démontage
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
window.clearTimeout(timeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn('flex-1 min-w-0', className)}>
|
||||
<Input
|
||||
ref={ref}
|
||||
type="text"
|
||||
value={localValue}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
className="bg-[var(--card)] border-[var(--border)] w-full"
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
SearchInput.displayName = 'SearchInput';
|
||||
|
||||
export { SearchInput };
|
||||
Reference in New Issue
Block a user