creacion de componentes dinamicos
This commit is contained in:
1 parent
ae415fef4e
commit
d74aa50845
13 files changed
+1448
No files matched your search
@@ -0,0 +1,122 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface SwitchProps {
|
||||
label?: React.ReactNode;
|
||||
description?: string;
|
||||
checked?: boolean;
|
||||
onChange?: (checked: boolean) => void;
|
||||
disabled?: boolean;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
checkedIcon?: React.ReactNode;
|
||||
uncheckedIcon?: React.ReactNode;
|
||||
id?: string;
|
||||
name?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const trackSizes = {
|
||||
sm: 'w-8 h-4.5',
|
||||
md: 'w-11 h-6',
|
||||
lg: 'w-14 h-7.5',
|
||||
};
|
||||
|
||||
const thumbSizes = {
|
||||
sm: 'w-3.5 h-3.5',
|
||||
md: 'w-5 h-5',
|
||||
lg: 'w-6.5 h-6.5',
|
||||
};
|
||||
|
||||
const translateSizes = {
|
||||
sm: 'translate-x-3.5',
|
||||
md: 'translate-x-5',
|
||||
lg: 'translate-x-6.5',
|
||||
};
|
||||
|
||||
export const Switch: React.FC<SwitchProps> = ({
|
||||
label,
|
||||
description,
|
||||
checked = false,
|
||||
onChange,
|
||||
disabled = false,
|
||||
size = 'md',
|
||||
checkedIcon,
|
||||
uncheckedIcon,
|
||||
id,
|
||||
name,
|
||||
className = '',
|
||||
}) => {
|
||||
const switchId = id || name || (typeof label === 'string' ? label.toLowerCase().replace(/\s+/g, '-') : undefined);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!disabled && onChange) {
|
||||
onChange(!checked);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === ' ' || e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handleClick();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`inline-flex items-start gap-3 select-none ${className}`}>
|
||||
{/* Switch Button */}
|
||||
<button
|
||||
id={switchId}
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={checked}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
className={`
|
||||
relative shrink-0 inline-flex items-center rounded-full p-0.5 cursor-pointer transition-colors duration-200 ease-in-out
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
|
||||
focus-visible:ring-cyan-500 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-950
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
${trackSizes[size]}
|
||||
${
|
||||
checked
|
||||
? 'bg-cyan-500 dark:bg-cyan-500'
|
||||
: 'bg-slate-300 dark:bg-slate-700 hover:bg-slate-400 dark:hover:bg-slate-600'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{/* Thumb */}
|
||||
<span
|
||||
className={`
|
||||
pointer-events-none flex items-center justify-center rounded-full bg-white shadow-md transform transition-transform duration-200 ease-in-out text-slate-800
|
||||
${thumbSizes[size]}
|
||||
${checked ? translateSizes[size] : 'translate-x-0'}
|
||||
`}
|
||||
>
|
||||
{checked ? checkedIcon : uncheckedIcon}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Label and description */}
|
||||
{(label || description) && (
|
||||
<div className="flex flex-col text-left cursor-pointer" onClick={handleClick}>
|
||||
{label && (
|
||||
<span
|
||||
className={`text-xs sm:text-sm font-medium transition-colors ${
|
||||
disabled
|
||||
? 'text-slate-400 dark:text-slate-600'
|
||||
: 'text-slate-800 dark:text-slate-200 hover:text-slate-950 dark:hover:text-white'
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{description && (
|
||||
<span className="text-xs text-slate-500 dark:text-slate-400">
|
||||
{description}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user