siesa-ui-kit 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1479 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1479 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -14
- package/claude/agents/siesa-ui-kit-specialist.md +0 -2401
- package/claude/prompts/component-template.md +0 -121
- package/claude/settings.local.json +0 -61
- package/docs/border-radius.md +0 -1261
- package/docs/colors.md +0 -832
- package/docs/dark-mode-guide.md +0 -1426
- package/docs/filters.md +0 -1243
- package/docs/icons.md +0 -1283
- package/docs/shadows.md +0 -1377
- package/docs/spacing.md +0 -1684
- package/docs/typography.md +0 -1268
- package/postcss.config.cjs +0 -6
- package/src/App.css +0 -42
- package/src/App.tsx +0 -8
- package/src/ButtonTest.tsx +0 -147
- package/src/assets/fonts/README.md +0 -261
- package/src/assets/fonts/SiesaBT/SiesaBT-Bold.otf +0 -0
- package/src/assets/fonts/SiesaBT/SiesaBT-Light.otf +0 -0
- package/src/assets/fonts/SiesaBT/SiesaBT-Regular.otf +0 -0
- package/src/assets/react.svg +0 -1
- package/src/components/Alert/Alert.stories.tsx +0 -332
- package/src/components/Alert/Alert.tsx +0 -106
- package/src/components/Alert/Alert.types.ts +0 -54
- package/src/components/Avatar/Avatar.stories.tsx +0 -494
- package/src/components/Avatar/Avatar.tsx +0 -143
- package/src/components/Avatar/Avatar.types.ts +0 -53
- package/src/components/Badge/Badge.stories.tsx +0 -339
- package/src/components/Badge/Badge.tsx +0 -278
- package/src/components/Badge/Badge.types.ts +0 -58
- package/src/components/Button/Button.stories.tsx +0 -950
- package/src/components/Button/Button.tsx +0 -337
- package/src/components/Button/Button.types.ts +0 -180
- package/src/components/Button/icons.tsx +0 -87
- package/src/components/Button/index.ts +0 -3
- package/src/components/Checkbox/Checkbox.stories.tsx +0 -453
- package/src/components/Checkbox/Checkbox.tsx +0 -208
- package/src/components/Checkbox/Checkbox.types.ts +0 -61
- package/src/components/DescriptionList/DescriptionList.stories.tsx +0 -250
- package/src/components/DescriptionList/DescriptionList.tsx +0 -96
- package/src/components/DescriptionList/DescriptionList.types.ts +0 -29
- package/src/components/Divider/Divider.stories.tsx +0 -263
- package/src/components/Divider/Divider.tsx +0 -80
- package/src/components/Divider/Divider.types.ts +0 -24
- package/src/components/Dropdown/Dropdown.stories.tsx +0 -552
- package/src/components/Dropdown/Dropdown.tsx +0 -422
- package/src/components/Dropdown/Dropdown.types.ts +0 -146
- package/src/components/Dropdown/README.md +0 -266
- package/src/components/Dropdown/icons.tsx +0 -72
- package/src/components/Dropdown/index.ts +0 -8
- package/src/components/Input/Input.stories.tsx +0 -583
- package/src/components/Input/Input.tsx +0 -204
- package/src/components/Input/Input.types.ts +0 -80
- package/src/components/Input/icons.tsx +0 -145
- package/src/components/Input/index.ts +0 -2
- package/src/components/LoginView/LoginView.stories.tsx +0 -148
- package/src/components/LoginView/LoginView.tsx +0 -426
- package/src/components/LoginView/LoginView.types.ts +0 -52
- package/src/components/LoginView/README.md +0 -396
- package/src/components/LoginView/icons.tsx +0 -85
- package/src/components/LoginView/index.ts +0 -3
- package/src/components/Navbar/Navbar.stories.tsx +0 -810
- package/src/components/Navbar/Navbar.tsx +0 -755
- package/src/components/Navbar/Navbar.types.ts +0 -219
- package/src/components/Navbar/README.md +0 -279
- package/src/components/Navbar/icons.tsx +0 -102
- package/src/components/Navbar/index.ts +0 -8
- package/src/components/NavigationBar/NavigationBar.stories.tsx +0 -406
- package/src/components/NavigationBar/NavigationBar.tsx +0 -246
- package/src/components/NavigationBar/NavigationBar.types.ts +0 -74
- package/src/components/NavigationBar/README.md +0 -469
- package/src/components/NavigationBar/index.ts +0 -2
- package/src/components/NavigationRail/NavigationRail.stories.tsx +0 -417
- package/src/components/NavigationRail/NavigationRail.tsx +0 -418
- package/src/components/NavigationRail/NavigationRail.types.ts +0 -109
- package/src/components/NavigationRail/README.md +0 -224
- package/src/components/NavigationRail/index.ts +0 -2
- package/src/components/Notification/Notification.stories.tsx +0 -513
- package/src/components/Notification/Notification.tsx +0 -145
- package/src/components/Notification/Notification.types.ts +0 -142
- package/src/components/Notification/README.md +0 -409
- package/src/components/Notification/index.ts +0 -3
- package/src/components/POSConvention/POSConvention.stories.tsx +0 -235
- package/src/components/POSConvention/POSConvention.tsx +0 -129
- package/src/components/POSConvention/POSConvention.types.ts +0 -38
- package/src/components/POSConvention/README.md +0 -123
- package/src/components/POSConvention/icons.tsx +0 -45
- package/src/components/POSConvention/index.ts +0 -3
- package/src/components/POSLocationButton/POSLocationButton.stories.tsx +0 -531
- package/src/components/POSLocationButton/POSLocationButton.tsx +0 -247
- package/src/components/POSLocationButton/POSLocationButton.types.ts +0 -87
- package/src/components/POSLocationButton/README.md +0 -253
- package/src/components/POSLocationButton/icons.tsx +0 -120
- package/src/components/POSLocationButton/index.ts +0 -14
- package/src/components/POSNumberButton/POSNumberButton.stories.tsx +0 -415
- package/src/components/POSNumberButton/POSNumberButton.tsx +0 -179
- package/src/components/POSNumberButton/POSNumberButton.types.ts +0 -51
- package/src/components/POSNumberButton/README.md +0 -321
- package/src/components/POSNumberButton/index.ts +0 -3
- package/src/components/POSProductButton/POSProductButton.stories.tsx +0 -318
- package/src/components/POSProductButton/POSProductButton.tsx +0 -152
- package/src/components/POSProductButton/POSProductButton.types.ts +0 -46
- package/src/components/POSProductButton/README.md +0 -269
- package/src/components/POSProductButton/index.ts +0 -2
- package/src/components/POSProductCard/POSProductCard.stories.tsx +0 -642
- package/src/components/POSProductCard/POSProductCard.tsx +0 -208
- package/src/components/POSProductCard/POSProductCard.types.ts +0 -76
- package/src/components/POSProductCard/README.md +0 -179
- package/src/components/POSProductCard/icons.tsx +0 -26
- package/src/components/POSProductCard/index.ts +0 -2
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.stories.tsx +0 -753
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.tsx +0 -332
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.types.ts +0 -119
- package/src/components/POSProductSidebarItems/README.md +0 -198
- package/src/components/POSProductSidebarItems/icons.tsx +0 -21
- package/src/components/POSProductSidebarItems/index.ts +0 -3
- package/src/components/POSTable/POSTable.stories.tsx +0 -737
- package/src/components/POSTable/POSTable.tsx +0 -401
- package/src/components/POSTable/POSTable.types.ts +0 -83
- package/src/components/POSTable/README.md +0 -286
- package/src/components/POSTable/index.ts +0 -7
- package/src/components/Pagination/Pagination.stories.tsx +0 -555
- package/src/components/Pagination/Pagination.tsx +0 -286
- package/src/components/Pagination/Pagination.types.ts +0 -93
- package/src/components/Pagination/README.md +0 -298
- package/src/components/Pagination/icons.tsx +0 -47
- package/src/components/Pagination/index.ts +0 -3
- package/src/components/Quantity/Quantity.stories.tsx +0 -457
- package/src/components/Quantity/Quantity.tsx +0 -289
- package/src/components/Quantity/Quantity.types.ts +0 -70
- package/src/components/Radio/Radio.stories.tsx +0 -523
- package/src/components/Radio/Radio.tsx +0 -170
- package/src/components/Radio/Radio.types.ts +0 -122
- package/src/components/Select/README.md +0 -299
- package/src/components/Select/Select.stories.tsx +0 -673
- package/src/components/Select/Select.tsx +0 -454
- package/src/components/Select/Select.types.ts +0 -148
- package/src/components/Select/icons.tsx +0 -50
- package/src/components/Select/index.ts +0 -3
- package/src/components/SignUpView/SignUpView.stories.tsx +0 -129
- package/src/components/SignUpView/SignUpView.tsx +0 -503
- package/src/components/SignUpView/SignUpView.types.ts +0 -58
- package/src/components/SignUpView/icons.tsx +0 -71
- package/src/components/SignUpView/index.ts +0 -3
- package/src/components/Switch/README.md +0 -112
- package/src/components/Switch/Switch.stories.tsx +0 -550
- package/src/components/Switch/Switch.tsx +0 -246
- package/src/components/Switch/Switch.types.ts +0 -67
- package/src/components/Table/README.md +0 -369
- package/src/components/Table/Table.stories.tsx +0 -805
- package/src/components/Table/Table.tsx +0 -688
- package/src/components/Table/Table.types.ts +0 -204
- package/src/components/Table/index.ts +0 -9
- package/src/components/Tabs/README.md +0 -201
- package/src/components/Tabs/Tabs.stories.tsx +0 -580
- package/src/components/Tabs/Tabs.tsx +0 -356
- package/src/components/Tabs/Tabs.types.ts +0 -127
- package/src/components/Tabs/icons.tsx +0 -129
- package/src/components/Tabs/index.ts +0 -11
- package/src/components/Textarea/Textarea.stories.tsx +0 -535
- package/src/components/Textarea/Textarea.tsx +0 -188
- package/src/components/Textarea/Textarea.types.ts +0 -54
- package/src/context/ThemeContext.tsx +0 -99
- package/src/context/index.ts +0 -1
- package/src/index.css +0 -29
- package/src/index.ts +0 -39
- package/src/main.tsx +0 -10
- package/src/views/ProductsView/ProductsView.stories.tsx +0 -344
- package/src/views/ProductsView/ProductsView.tsx +0 -480
- package/src/views/ProductsView/ProductsView.types.ts +0 -238
- package/src/views/ProductsView/README.md +0 -312
- package/src/views/ProductsView/icons.tsx +0 -38
- package/src/views/ProductsView/index.ts +0 -8
- package/src/views/RecoverPasswordView/README.md +0 -269
- package/src/views/RecoverPasswordView/RecoverPasswordView.stories.tsx +0 -131
- package/src/views/RecoverPasswordView/RecoverPasswordView.tsx +0 -376
- package/src/views/RecoverPasswordView/RecoverPasswordView.types.ts +0 -56
- package/src/views/RecoverPasswordView/icons.tsx +0 -17
- package/src/views/RecoverPasswordView/index.ts +0 -2
- package/src/views/TableLayoutView/README.md +0 -268
- package/src/views/TableLayoutView/TableLayoutView.stories.tsx +0 -235
- package/src/views/TableLayoutView/TableLayoutView.tsx +0 -461
- package/src/views/TableLayoutView/TableLayoutView.types.ts +0 -209
- package/src/views/TableLayoutView/icons.tsx +0 -113
- package/src/views/TableLayoutView/index.ts +0 -6
- package/storybook/main.ts +0 -20
- package/storybook/preview.tsx +0 -84
- package/storybook/vitest.setup.ts +0 -7
- package/tailwind.config.js +0 -128
- /package/{public → dist}/,Business Logo.png +0 -0
- /package/{public → dist}/.Siesa Logo.png +0 -0
- /package/{public → dist}/bg_siesa.png +0 -0
- /package/{public → dist}/siesa_logo_mobile.png +0 -0
- /package/{public → dist}/vite.svg +0 -0
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
DropdownProps,
|
|
4
|
-
DropdownItemProps,
|
|
5
|
-
DropdownHeadingProps,
|
|
6
|
-
DropdownDividerProps,
|
|
7
|
-
} from './Dropdown.types';
|
|
8
|
-
import { ChevronDownIcon } from './icons';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Componente Dropdown del sistema de diseño Siesa
|
|
12
|
-
* Basado en especificaciones de Figma con Tailwind CSS
|
|
13
|
-
*
|
|
14
|
-
* Mejores prácticas implementadas:
|
|
15
|
-
* - Orden de modificadores: {responsive}:{dark}:{state}:{utility}
|
|
16
|
-
* - Dark mode con estrategia 'class' (darkMode: 'class')
|
|
17
|
-
* - Tokens de color consistentes con la documentación
|
|
18
|
-
* - Type safety con TypeScript estricto
|
|
19
|
-
* - Accesibilidad con ARIA labels y keyboard navigation
|
|
20
|
-
* - Cierre automático al hacer click fuera
|
|
21
|
-
*
|
|
22
|
-
* @see docs/colors.md - Sistema de colores
|
|
23
|
-
* @see docs/typography.md - Sistema tipográfico
|
|
24
|
-
* @see docs/spacing.md - Sistema de espaciado
|
|
25
|
-
* @see docs/shadows.md - Sistema de sombras
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```tsx
|
|
29
|
-
* <Dropdown
|
|
30
|
-
* placeholder="Options"
|
|
31
|
-
* items={[
|
|
32
|
-
* { children: 'Account', icon: <UserIcon /> },
|
|
33
|
-
* { children: 'Settings', icon: <CogIcon /> },
|
|
34
|
-
* { isDivider: true },
|
|
35
|
-
* { children: 'Logout' },
|
|
36
|
-
* ]}
|
|
37
|
-
* />
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
export const Dropdown: React.FC<DropdownProps> = ({
|
|
41
|
-
variant = 'default',
|
|
42
|
-
children,
|
|
43
|
-
items,
|
|
44
|
-
open: controlledOpen,
|
|
45
|
-
onOpenChange,
|
|
46
|
-
disabled = false,
|
|
47
|
-
className = '',
|
|
48
|
-
menuClassName = '',
|
|
49
|
-
ariaLabel,
|
|
50
|
-
placeholder = 'Options',
|
|
51
|
-
}) => {
|
|
52
|
-
const [internalOpen, setInternalOpen] = useState(false);
|
|
53
|
-
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
54
|
-
|
|
55
|
-
// Determinar si es controlado o no controlado
|
|
56
|
-
const isControlled = controlledOpen !== undefined;
|
|
57
|
-
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
58
|
-
|
|
59
|
-
// Función para cambiar el estado
|
|
60
|
-
const handleToggle = () => {
|
|
61
|
-
if (disabled) return;
|
|
62
|
-
|
|
63
|
-
const newOpen = !isOpen;
|
|
64
|
-
|
|
65
|
-
if (!isControlled) {
|
|
66
|
-
setInternalOpen(newOpen);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
onOpenChange?.(newOpen);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// Cerrar al hacer click fuera
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
const handleClickOutside = (event: MouseEvent) => {
|
|
75
|
-
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
|
76
|
-
if (!isControlled) {
|
|
77
|
-
setInternalOpen(false);
|
|
78
|
-
}
|
|
79
|
-
onOpenChange?.(false);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
if (isOpen) {
|
|
84
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
85
|
-
return () => {
|
|
86
|
-
document.removeEventListener('mousedown', handleClickOutside);
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}, [isOpen, isControlled, onOpenChange]);
|
|
90
|
-
|
|
91
|
-
// Cerrar al presionar Escape
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
const handleEscape = (event: KeyboardEvent) => {
|
|
94
|
-
if (event.key === 'Escape' && isOpen) {
|
|
95
|
-
if (!isControlled) {
|
|
96
|
-
setInternalOpen(false);
|
|
97
|
-
}
|
|
98
|
-
onOpenChange?.(false);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
if (isOpen) {
|
|
103
|
-
document.addEventListener('keydown', handleEscape);
|
|
104
|
-
return () => {
|
|
105
|
-
document.removeEventListener('keydown', handleEscape);
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}, [isOpen, isControlled, onOpenChange]);
|
|
109
|
-
|
|
110
|
-
// Handler para item click
|
|
111
|
-
const handleItemClick = (item: DropdownItemProps) => {
|
|
112
|
-
if (item.disabled || item.isDivider || item.isHeading) return;
|
|
113
|
-
|
|
114
|
-
// Ejecutar el onClick del item
|
|
115
|
-
if (item.onClick) {
|
|
116
|
-
item.onClick({} as React.MouseEvent<HTMLButtonElement>);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Cerrar el dropdown
|
|
120
|
-
if (!isControlled) {
|
|
121
|
-
setInternalOpen(false);
|
|
122
|
-
}
|
|
123
|
-
onOpenChange?.(false);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// ===== CLASES DEL TRIGGER BUTTON =====
|
|
127
|
-
const triggerClasses = [
|
|
128
|
-
// Base
|
|
129
|
-
'inline-flex',
|
|
130
|
-
'items-center',
|
|
131
|
-
'justify-center',
|
|
132
|
-
'rounded-lg',
|
|
133
|
-
'font-bold',
|
|
134
|
-
'text-sm',
|
|
135
|
-
'whitespace-nowrap',
|
|
136
|
-
'transition-all',
|
|
137
|
-
'duration-150',
|
|
138
|
-
|
|
139
|
-
// Variant-specific sizing
|
|
140
|
-
variant === 'icon-only' ? 'w-9 h-9' : 'gap-3 px-3 py-2',
|
|
141
|
-
|
|
142
|
-
// Colores y estados (Light Mode)
|
|
143
|
-
'bg-bg-primary',
|
|
144
|
-
'text-content-secondary',
|
|
145
|
-
'border',
|
|
146
|
-
'border-border-primary',
|
|
147
|
-
'hover:bg-background-secondary',
|
|
148
|
-
'active:scale-95',
|
|
149
|
-
|
|
150
|
-
// Dark Mode
|
|
151
|
-
'dark:bg-dark-bg-primary',
|
|
152
|
-
'dark:text-content-secondary',
|
|
153
|
-
'dark:border-dark-border-primary',
|
|
154
|
-
'dark:hover:bg-dark-bg-primary',
|
|
155
|
-
|
|
156
|
-
// Focus ring
|
|
157
|
-
'focus:outline-none',
|
|
158
|
-
'focus:ring-2',
|
|
159
|
-
'focus:ring-primary-custom-400',
|
|
160
|
-
'focus:ring-offset-2',
|
|
161
|
-
'dark:focus:ring-dark-border-custom',
|
|
162
|
-
'dark:focus:ring-offset-dark-bg-primary',
|
|
163
|
-
|
|
164
|
-
// Disabled
|
|
165
|
-
disabled && 'opacity-50',
|
|
166
|
-
disabled && 'cursor-not-allowed',
|
|
167
|
-
disabled && 'pointer-events-none',
|
|
168
|
-
|
|
169
|
-
// Custom classes
|
|
170
|
-
className,
|
|
171
|
-
]
|
|
172
|
-
.filter(Boolean)
|
|
173
|
-
.join(' ')
|
|
174
|
-
.replace(/\s+/g, ' ')
|
|
175
|
-
.trim();
|
|
176
|
-
|
|
177
|
-
// ===== CLASES DEL MENU =====
|
|
178
|
-
const menuClasses = [
|
|
179
|
-
// Base
|
|
180
|
-
'absolute',
|
|
181
|
-
'top-full',
|
|
182
|
-
'left-0',
|
|
183
|
-
'mt-2',
|
|
184
|
-
'min-w-[182px]',
|
|
185
|
-
'rounded-xl',
|
|
186
|
-
'p-1',
|
|
187
|
-
'border',
|
|
188
|
-
'z-50',
|
|
189
|
-
|
|
190
|
-
// Colores (Light Mode)
|
|
191
|
-
'bg-background-secondary',
|
|
192
|
-
'border-border-primary',
|
|
193
|
-
|
|
194
|
-
// Dark Mode
|
|
195
|
-
'dark:bg-dark-bg-primary',
|
|
196
|
-
'dark:border-dark-border-primary',
|
|
197
|
-
|
|
198
|
-
// Shadow
|
|
199
|
-
'shadow-menu',
|
|
200
|
-
|
|
201
|
-
// Custom classes
|
|
202
|
-
menuClassName,
|
|
203
|
-
]
|
|
204
|
-
.filter(Boolean)
|
|
205
|
-
.join(' ')
|
|
206
|
-
.replace(/\s+/g, ' ')
|
|
207
|
-
.trim();
|
|
208
|
-
|
|
209
|
-
return (
|
|
210
|
-
<div ref={dropdownRef} className="relative inline-block">
|
|
211
|
-
{/* Trigger Button */}
|
|
212
|
-
<button
|
|
213
|
-
type="button"
|
|
214
|
-
className={triggerClasses}
|
|
215
|
-
onClick={handleToggle}
|
|
216
|
-
disabled={disabled}
|
|
217
|
-
aria-label={ariaLabel || (variant === 'icon-only' ? 'Abrir menú' : undefined)}
|
|
218
|
-
aria-haspopup="true"
|
|
219
|
-
aria-expanded={isOpen}
|
|
220
|
-
>
|
|
221
|
-
{variant === 'default' && <span>{children || placeholder}</span>}
|
|
222
|
-
<ChevronDownIcon />
|
|
223
|
-
</button>
|
|
224
|
-
|
|
225
|
-
{/* Dropdown Menu */}
|
|
226
|
-
{isOpen && (
|
|
227
|
-
<div className={menuClasses}>
|
|
228
|
-
{items.map((item, index) => {
|
|
229
|
-
if (item.isDivider) {
|
|
230
|
-
return <DropdownDivider key={index} className={item.className} />;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (item.isHeading) {
|
|
234
|
-
return (
|
|
235
|
-
<DropdownHeading key={index} className={item.className}>
|
|
236
|
-
{item.children}
|
|
237
|
-
</DropdownHeading>
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return (
|
|
242
|
-
<DropdownItem
|
|
243
|
-
key={index}
|
|
244
|
-
{...item}
|
|
245
|
-
onClick={() => handleItemClick(item)}
|
|
246
|
-
/>
|
|
247
|
-
);
|
|
248
|
-
})}
|
|
249
|
-
</div>
|
|
250
|
-
)}
|
|
251
|
-
</div>
|
|
252
|
-
);
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Componente DropdownItem
|
|
257
|
-
* Item individual dentro del menú dropdown
|
|
258
|
-
*
|
|
259
|
-
* @example
|
|
260
|
-
* ```tsx
|
|
261
|
-
* <DropdownItem icon={<UserIcon />} shortcut="⌘ P">
|
|
262
|
-
* Profile
|
|
263
|
-
* </DropdownItem>
|
|
264
|
-
* ```
|
|
265
|
-
*/
|
|
266
|
-
export const DropdownItem: React.FC<DropdownItemProps> = ({
|
|
267
|
-
children,
|
|
268
|
-
icon,
|
|
269
|
-
description,
|
|
270
|
-
shortcut,
|
|
271
|
-
disabled = false,
|
|
272
|
-
selected = false,
|
|
273
|
-
onClick,
|
|
274
|
-
className = '',
|
|
275
|
-
}) => {
|
|
276
|
-
// ===== CLASES DEL ITEM =====
|
|
277
|
-
const itemClasses = [
|
|
278
|
-
// Base
|
|
279
|
-
'flex',
|
|
280
|
-
'items-center',
|
|
281
|
-
'gap-3',
|
|
282
|
-
'px-4',
|
|
283
|
-
'py-2',
|
|
284
|
-
'rounded-lg',
|
|
285
|
-
'text-sm',
|
|
286
|
-
'w-full',
|
|
287
|
-
'text-left',
|
|
288
|
-
'transition-colors',
|
|
289
|
-
'duration-150',
|
|
290
|
-
|
|
291
|
-
// Colores y estados (Light Mode)
|
|
292
|
-
'text-content-primary',
|
|
293
|
-
!disabled && 'hover:bg-white',
|
|
294
|
-
selected && 'bg-white',
|
|
295
|
-
|
|
296
|
-
// Dark Mode
|
|
297
|
-
'dark:text-dark-content-primary',
|
|
298
|
-
!disabled && 'dark:hover:bg-dark-bg-primary',
|
|
299
|
-
selected && 'dark:bg-dark-bg-primary',
|
|
300
|
-
|
|
301
|
-
// Disabled
|
|
302
|
-
disabled && 'opacity-50',
|
|
303
|
-
disabled && 'cursor-not-allowed',
|
|
304
|
-
!disabled && 'cursor-pointer',
|
|
305
|
-
|
|
306
|
-
// Custom classes
|
|
307
|
-
className,
|
|
308
|
-
]
|
|
309
|
-
.filter(Boolean)
|
|
310
|
-
.join(' ')
|
|
311
|
-
.replace(/\s+/g, ' ')
|
|
312
|
-
.trim();
|
|
313
|
-
|
|
314
|
-
return (
|
|
315
|
-
<button
|
|
316
|
-
type="button"
|
|
317
|
-
className={itemClasses}
|
|
318
|
-
onClick={onClick}
|
|
319
|
-
disabled={disabled}
|
|
320
|
-
>
|
|
321
|
-
{/* Icon */}
|
|
322
|
-
{icon && (
|
|
323
|
-
<span className="inline-flex items-center justify-center w-4 h-4 text-content-secondary dark:text-content-secondary">
|
|
324
|
-
{icon}
|
|
325
|
-
</span>
|
|
326
|
-
)}
|
|
327
|
-
|
|
328
|
-
{/* Content */}
|
|
329
|
-
<div className="flex-1 min-w-0">
|
|
330
|
-
{/* Label */}
|
|
331
|
-
<div className="text-content-primary dark:text-dark-content-primary">
|
|
332
|
-
{children}
|
|
333
|
-
</div>
|
|
334
|
-
|
|
335
|
-
{/* Description */}
|
|
336
|
-
{description && (
|
|
337
|
-
<div className="text-xs text-content-secondary dark:text-content-secondary mt-0.5">
|
|
338
|
-
{description}
|
|
339
|
-
</div>
|
|
340
|
-
)}
|
|
341
|
-
</div>
|
|
342
|
-
|
|
343
|
-
{/* Shortcut */}
|
|
344
|
-
{shortcut && (
|
|
345
|
-
<span className="text-xs text-content-secondary dark:text-content-secondary ml-auto whitespace-nowrap">
|
|
346
|
-
{shortcut}
|
|
347
|
-
</span>
|
|
348
|
-
)}
|
|
349
|
-
</button>
|
|
350
|
-
);
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Componente DropdownHeading
|
|
355
|
-
* Encabezado de sección dentro del menú dropdown
|
|
356
|
-
*
|
|
357
|
-
* @example
|
|
358
|
-
* ```tsx
|
|
359
|
-
* <DropdownHeading>My events</DropdownHeading>
|
|
360
|
-
* ```
|
|
361
|
-
*/
|
|
362
|
-
export const DropdownHeading: React.FC<DropdownHeadingProps> = ({
|
|
363
|
-
children,
|
|
364
|
-
className = '',
|
|
365
|
-
}) => {
|
|
366
|
-
// ===== CLASES DEL HEADING =====
|
|
367
|
-
const headingClasses = [
|
|
368
|
-
// Base
|
|
369
|
-
'px-4',
|
|
370
|
-
'py-1',
|
|
371
|
-
'text-xs',
|
|
372
|
-
'font-normal',
|
|
373
|
-
|
|
374
|
-
// Colores
|
|
375
|
-
'text-content-tertiary',
|
|
376
|
-
|
|
377
|
-
// Dark Mode
|
|
378
|
-
'dark:text-content-tertiary',
|
|
379
|
-
|
|
380
|
-
// Custom classes
|
|
381
|
-
className,
|
|
382
|
-
]
|
|
383
|
-
.filter(Boolean)
|
|
384
|
-
.join(' ')
|
|
385
|
-
.replace(/\s+/g, ' ')
|
|
386
|
-
.trim();
|
|
387
|
-
|
|
388
|
-
return <div className={headingClasses}>{children}</div>;
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Componente DropdownDivider
|
|
393
|
-
* Separador visual entre items del menú dropdown
|
|
394
|
-
*
|
|
395
|
-
* @example
|
|
396
|
-
* ```tsx
|
|
397
|
-
* <DropdownDivider />
|
|
398
|
-
* ```
|
|
399
|
-
*/
|
|
400
|
-
export const DropdownDivider: React.FC<DropdownDividerProps> = ({
|
|
401
|
-
className = '',
|
|
402
|
-
}) => {
|
|
403
|
-
// ===== CLASES DEL DIVIDER =====
|
|
404
|
-
const dividerClasses = [
|
|
405
|
-
// Base
|
|
406
|
-
'px-4',
|
|
407
|
-
'py-1',
|
|
408
|
-
|
|
409
|
-
// Custom classes
|
|
410
|
-
className,
|
|
411
|
-
]
|
|
412
|
-
.filter(Boolean)
|
|
413
|
-
.join(' ')
|
|
414
|
-
.replace(/\s+/g, ' ')
|
|
415
|
-
.trim();
|
|
416
|
-
|
|
417
|
-
return (
|
|
418
|
-
<div className={dividerClasses}>
|
|
419
|
-
<div className="h-px bg-border-primary dark:bg-dark-border-primary" />
|
|
420
|
-
</div>
|
|
421
|
-
);
|
|
422
|
-
};
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, MouseEvent } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Props del componente Dropdown (trigger button)
|
|
5
|
-
*/
|
|
6
|
-
export interface DropdownProps {
|
|
7
|
-
/**
|
|
8
|
-
* Variante visual del dropdown
|
|
9
|
-
* - 'default': Botón con texto + ícono
|
|
10
|
-
* - 'icon-only': Solo ícono (sin texto)
|
|
11
|
-
* @default 'default'
|
|
12
|
-
*/
|
|
13
|
-
variant?: 'default' | 'icon-only';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Texto o contenido del botón trigger
|
|
17
|
-
*/
|
|
18
|
-
children?: ReactNode;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Items del menú dropdown
|
|
22
|
-
*/
|
|
23
|
-
items: DropdownItemProps[];
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Si el dropdown está abierto (controlado)
|
|
27
|
-
*/
|
|
28
|
-
open?: boolean;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Callback cuando el dropdown cambia de estado
|
|
32
|
-
*/
|
|
33
|
-
onOpenChange?: (open: boolean) => void;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Si el dropdown está deshabilitado
|
|
37
|
-
* @default false
|
|
38
|
-
*/
|
|
39
|
-
disabled?: boolean;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Clases CSS adicionales para el trigger
|
|
43
|
-
*/
|
|
44
|
-
className?: string;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Clases CSS adicionales para el menú
|
|
48
|
-
*/
|
|
49
|
-
menuClassName?: string;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Label para accesibilidad (ARIA)
|
|
53
|
-
*/
|
|
54
|
-
ariaLabel?: string;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Placeholder cuando no hay children
|
|
58
|
-
* @default 'Options'
|
|
59
|
-
*/
|
|
60
|
-
placeholder?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Props del componente DropdownItem
|
|
65
|
-
*/
|
|
66
|
-
export interface DropdownItemProps {
|
|
67
|
-
/**
|
|
68
|
-
* Contenido del item
|
|
69
|
-
* No requerido cuando isDivider es true
|
|
70
|
-
*/
|
|
71
|
-
children?: ReactNode;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Icono a mostrar antes del texto (izquierda)
|
|
75
|
-
*/
|
|
76
|
-
icon?: ReactNode;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Descripción secundaria del item
|
|
80
|
-
*/
|
|
81
|
-
description?: string;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Atajo de teclado a mostrar (derecha)
|
|
85
|
-
*/
|
|
86
|
-
shortcut?: string;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Si el item está deshabilitado
|
|
90
|
-
* @default false
|
|
91
|
-
*/
|
|
92
|
-
disabled?: boolean;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Si el item está seleccionado
|
|
96
|
-
* @default false
|
|
97
|
-
*/
|
|
98
|
-
selected?: boolean;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Función onClick del item
|
|
102
|
-
*/
|
|
103
|
-
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Clases CSS adicionales
|
|
107
|
-
*/
|
|
108
|
-
className?: string;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Indica si este item es un divider (separador)
|
|
112
|
-
* @default false
|
|
113
|
-
*/
|
|
114
|
-
isDivider?: boolean;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Indica si este item es un heading (encabezado)
|
|
118
|
-
* @default false
|
|
119
|
-
*/
|
|
120
|
-
isHeading?: boolean;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Props del componente DropdownHeading
|
|
125
|
-
*/
|
|
126
|
-
export interface DropdownHeadingProps {
|
|
127
|
-
/**
|
|
128
|
-
* Texto del heading
|
|
129
|
-
*/
|
|
130
|
-
children: ReactNode;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Clases CSS adicionales
|
|
134
|
-
*/
|
|
135
|
-
className?: string;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Props del componente DropdownDivider
|
|
140
|
-
*/
|
|
141
|
-
export interface DropdownDividerProps {
|
|
142
|
-
/**
|
|
143
|
-
* Clases CSS adicionales
|
|
144
|
-
*/
|
|
145
|
-
className?: string;
|
|
146
|
-
}
|