@imj_media/ui 1.10.3 → 1.10.5
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/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/catalog/design-index.json +2857 -0
- package/catalog/design-index.schema.json +131 -0
- package/catalog/legacy-modules.json +15 -0
- package/dist/index.css +1 -1
- package/dist/index.esm.js +8263 -8165
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/dist/modules/RangeBar/components/organisms/RangeSelector.d.ts +2 -2
- package/dist/modules/RangeBar/components/organisms/RangeSelector.d.ts.map +1 -1
- package/dist/modules/RangeBar/stories/RangeBar.stories.d.ts +2 -0
- package/dist/modules/RangeBar/stories/RangeBar.stories.d.ts.map +1 -1
- package/dist/modules/RangeBar/utils/rangeSelectorDisplayWidth.d.ts +2 -0
- package/dist/modules/RangeBar/utils/rangeSelectorDisplayWidth.d.ts.map +1 -1
- package/dist/modules/Table/Table.d.ts.map +1 -1
- package/dist/modules/Table/components/organisms/TableToolbar.d.ts +1 -1
- package/dist/modules/Table/components/organisms/TableToolbar.d.ts.map +1 -1
- package/dist/modules/Table/hooks/useTableColumns.d.ts.map +1 -1
- package/dist/modules/Table/hooks/useTableConfig.d.ts.map +1 -1
- package/dist/modules/Table/hooks/useTableFilters.d.ts +2 -1
- package/dist/modules/Table/hooks/useTableFilters.d.ts.map +1 -1
- package/dist/modules/Table/hooks/useTableSelection.d.ts +5 -0
- package/dist/modules/Table/hooks/useTableSelection.d.ts.map +1 -1
- package/dist/modules/Table/stories/Table.stories.d.ts +12 -0
- package/dist/modules/Table/stories/Table.stories.d.ts.map +1 -1
- package/dist/modules/Table/utils/columnLockable.d.ts +10 -0
- package/dist/modules/Table/utils/columnLockable.d.ts.map +1 -1
- package/dist/modules/Table/utils/columnManagement.d.ts.map +1 -1
- package/dist/modules/Table/utils/selection.d.ts +6 -0
- package/dist/modules/Table/utils/selection.d.ts.map +1 -1
- package/dist/modules/Table/utils/tableColumnTransforms.d.ts.map +1 -1
- package/dist/shared/types/table.d.ts +44 -1
- package/dist/shared/types/table.d.ts.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,2857 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"package": "@imj_media/ui",
|
|
4
|
+
"version": "1.10.5",
|
|
5
|
+
"indexedAt": "2026-05-25T20:20:35.330Z",
|
|
6
|
+
"orbitTokensVersion": "1.3.1",
|
|
7
|
+
"modules": [
|
|
8
|
+
{
|
|
9
|
+
"id": "Accordion",
|
|
10
|
+
"path": "src/modules/Accordion",
|
|
11
|
+
"legacy": false,
|
|
12
|
+
"compositionType": 2,
|
|
13
|
+
"exports": [
|
|
14
|
+
{
|
|
15
|
+
"name": "Accordion",
|
|
16
|
+
"kind": "component",
|
|
17
|
+
"description": {
|
|
18
|
+
"primary": "storybook",
|
|
19
|
+
"storybook": "El componente Accordion permite mostrar contenido colapsable con un encabezado. Útil para organizar información de forma compacta.",
|
|
20
|
+
"jsdoc": "Accordion - Componente de acordeón expandible\nComponente que permite mostrar/ocultar contenido de forma expandible.\nSoporta múltiples items, estados controlados y no controlados.",
|
|
21
|
+
"confidence": "high"
|
|
22
|
+
},
|
|
23
|
+
"examples": [
|
|
24
|
+
"import { Accordion } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Accordion\n id=\"accordion-1\"\n title=\"Título del Accordion\"\n subtitle=\"Subtítulo opcional\"\n >\n <div className=\"ui-p-4\">\n <p>Contenido del accordion</p>\n </div>\n </Accordion>\n );\n}",
|
|
25
|
+
"import { Accordion } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Accordion\n id=\"accordion-2\"\n title=\"Accordion Abierto\"\n defaultOpen={true}\n >\n <div className=\"ui-p-4\">\n <p>Contenido visible desde el inicio</p>\n </div>\n </Accordion>\n );\n}",
|
|
26
|
+
"import { Accordion } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Accordion\n id=\"accordion-3\"\n title=\"Accordion Deshabilitado\"\n disabled={true}\n >\n <div className=\"ui-p-4\">\n <p>Contenido no accesible</p>\n </div>\n </Accordion>\n );\n}",
|
|
27
|
+
"import { Accordion } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Accordion\n id=\"accordion-4\"\n title=\"Accordion sin Subtítulo\"\n >\n <div className=\"ui-p-4\">\n <p>Contenido del accordion</p>\n </div>\n </Accordion>\n );\n}",
|
|
28
|
+
"import { Accordion } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <div className=\"ui-space-y-4\">\n <Accordion id=\"accordion-5\" title=\"Primera Sección\">\n <div className=\"ui-p-4\">\n <p>Contenido de la primera sección</p>\n </div>\n </Accordion>\n \n <Accordion \n id=\"accordion-6\" \n title=\"Segunda Sección\"\n defaultOpen={true}\n >\n <div className=\"ui-p-4\">\n <p>Contenido de la segunda sección</p>\n </div>\n </Accordion>\n \n <Accordion id=\"accordion-7\" title=\"Tercera Sección\">\n <div className=\"ui-p-4\">\n <p>Contenido de la tercera sección</p>\n </div>\n </Accordion>\n </div>\n );\n}"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"compositionRecipe": {
|
|
33
|
+
"pieces": [
|
|
34
|
+
"Accordion",
|
|
35
|
+
"AccordionHeader",
|
|
36
|
+
"AccordionContent"
|
|
37
|
+
],
|
|
38
|
+
"steps": [
|
|
39
|
+
"Pasa id y title obligatorios en Accordion (API de contenedor).",
|
|
40
|
+
"El children del accordion es el contenido visible al expandir.",
|
|
41
|
+
"Para múltiples secciones, repite Accordion o usa items según la story del módulo."
|
|
42
|
+
],
|
|
43
|
+
"storyRefs": [
|
|
44
|
+
"Accordion.stories.tsx:Default"
|
|
45
|
+
],
|
|
46
|
+
"snippet": "<Accordion\n id=\"section-1\"\n title=\"Sección\"\n subtitle=\"Opcional\"\n defaultOpen={false}\n>\n Contenido colapsable\n</Accordion>"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "Alert",
|
|
51
|
+
"path": "src/modules/Alert",
|
|
52
|
+
"legacy": false,
|
|
53
|
+
"compositionType": 1,
|
|
54
|
+
"exports": [
|
|
55
|
+
{
|
|
56
|
+
"name": "Alert",
|
|
57
|
+
"kind": "component",
|
|
58
|
+
"description": {
|
|
59
|
+
"primary": "storybook",
|
|
60
|
+
"storybook": "El componente Alert permite mostrar mensajes informativos, de éxito, advertencia o error con diferentes variantes visuales.",
|
|
61
|
+
"jsdoc": "Alert - Componente de alerta\nTokens semánticos de Figma:\n- Padding: 16px (space_16) para md, reducido para sm\n- Gap: 16px (space_16) entre secciones\n- Border radius: control-sm (8px)\n- Border width: 1px",
|
|
62
|
+
"confidence": "high"
|
|
63
|
+
},
|
|
64
|
+
"examples": [
|
|
65
|
+
"import { Alert } from '@/modules/Alert';\n\n export default function Example() {\n return (\n <Alert \n color=\"success\" \n message=\"Operación completada exitosamente\" \n title=\"Éxito\" \n open={true} \n />\n )\n }",
|
|
66
|
+
"<Alert color=\"success\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"info\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"warning\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"danger\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"success\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"info\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"warning\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"danger\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />",
|
|
67
|
+
"<Alert\n color=\"success\"\n message=\"Operación completada exitosamente\"\n title=\"Éxito\"\n description=\"Los cambios se han guardado correctamente en la base de datos.\"\n open={true}\n />\n <Alert\n color=\"danger\"\n message=\"Ha ocurrido un error inesperado\"\n title=\"Error\"\n description=\"Por favor, intenta nuevamente o contacta al soporte técnico si el problema persiste.\"\n open={true}\n />\n <Alert\n color=\"info\"\n message=\"Información importante para el usuario\"\n title=\"Información\"\n description=\"Esta acción puede tardar unos minutos en completarse. Por favor, espera hasta que finalice.\"\n open={true}\n />\n <Alert\n color=\"warning\"\n message=\"Advertencia antes de continuar\"\n title=\"Advertencia\"\n description=\"Esta acción no se puede deshacer. Asegúrate de que realmente deseas continuar.\"\n open={true}\n />\n <Alert\n color=\"neutral\"\n message=\"Mensaje neutral sin color específico\"\n title=\"Notificación\"\n description=\"Este es un mensaje informativo que no requiere acción inmediata por parte del usuario.\"\n open={true}\n />",
|
|
68
|
+
"import { Alert } from '@/modules/Alert';\n\n export default function Example() {\n return (\n <Alert \n color=\"success\" \n message=\"Operación completada exitosamente\" \n title=\"Éxito\" \n open={true} \n />\n )\n }",
|
|
69
|
+
"<Alert color=\"success\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"info\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"warning\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"danger\" variant=\"contained\" message=\"Variante contained (por defecto)\" title=\"Contained\" open={true} />\n <Alert color=\"success\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"info\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"warning\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />\n <Alert color=\"danger\" variant=\"outlined\" message=\"Variante outlined con borde\" title=\"Outlined\" open={true} />"
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "AlertDialog",
|
|
76
|
+
"path": "src/modules/AlertDialog",
|
|
77
|
+
"legacy": false,
|
|
78
|
+
"compositionType": 1,
|
|
79
|
+
"exports": [
|
|
80
|
+
{
|
|
81
|
+
"name": "AlertDialog",
|
|
82
|
+
"kind": "component",
|
|
83
|
+
"description": {
|
|
84
|
+
"primary": "storybook",
|
|
85
|
+
"storybook": "El componente AlertDialog permite a los usuarios realizar acciones y tomar decisiones con un solo toque.",
|
|
86
|
+
"jsdoc": "AlertDialog - Componente de diálogo de confirmación/alert\nComponente de diálogo modal especializado para confirmaciones y alertas.\nSoporta texto de confirmación requerido, iconos personalizados y múltiples tamaños.",
|
|
87
|
+
"confidence": "high"
|
|
88
|
+
},
|
|
89
|
+
"examples": [
|
|
90
|
+
"import { AlertDialog } from '@imj_media/ui';\n const [isOpen, setIsOpen] = useState(false);\n\n export default function Example() {\n return <AlertDialog\n title='Eliminar borrador'\n iconContent={faHardDrive}\n heading='¿Estás seguro?'\n subheading='Si eliminas este borrador, también se borrarán todas sus tareas y conexiones con otros borradores.'\n icon={faBan}\n label=\"Confirmar eliminación\"\n confirmationText=\"EliminarBorrador\"\n isOpen={isOpen} onClose={() => setIsOpen(false)}\n onConfirm={() => { console.log('onConfirm') }}\n placeholder='Escribe la palabra de confirmación'\n />\n }",
|
|
91
|
+
"import { AlertDialog } from '@imj_media/ui';\nimport { useState } from 'react';\n\nexport default function SizesExample() {\n const [isOpen, setIsOpen] = useState(false);\n \n return (\n <AlertDialog\n size=\"lg\" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\n title='Confirmar acción'\n iconContent={faInfoCircle}\n heading='¿Confirmar?'\n subheading='Este AlertDialog usa un tamaño grande.'\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n onConfirm={() => console.log('Confirmado')}\n successButtonText=\"Aceptar\"\n successButtonColor=\"primary\"\n />\n );\n}",
|
|
92
|
+
"import { AlertDialog } from '@/modules/AlertDialog';\nimport { faTrash, faBan } from '@fortawesome/pro-duotone-svg-icons';\nimport { useState } from 'react';\n\nexport default function DuotoneExample() {\n const [isOpen, setIsOpen] = useState(false);\n \n return (\n <AlertDialog\n title='Eliminar borrador'\n iconContent={faBan}\n iconContentDuotonePrimary=\"danger\"\n iconContentDuotoneSecondary=\"red\"\n iconContentDuotoneOpacityPrimary={1}\n iconContentDuotoneOpacitySecondary={0.4}\n icon={faTrash}\n iconDuotonePrimary=\"danger\"\n iconDuotoneSecondary=\"red\"\n iconDuotoneOpacityPrimary={1}\n iconDuotoneOpacitySecondary={0.4}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n onConfirm={() => console.log('Confirmado')}\n />\n );\n}",
|
|
93
|
+
"import { AlertDialog } from '@imj_media/ui';\n const [isOpen, setIsOpen] = useState(false);\n\n export default function Example() {\n return <AlertDialog\n title='Eliminar borrador'\n iconContent={faHardDrive}\n heading='¿Estás seguro?'\n subheading='Si eliminas este borrador, también se borrarán todas sus tareas y conexiones con otros borradores.'\n icon={faBan}\n label=\"Confirmar eliminación\"\n confirmationText=\"EliminarBorrador\"\n isOpen={isOpen} onClose={() => setIsOpen(false)}\n onConfirm={() => { console.log('onConfirm') }}\n placeholder='Escribe la palabra de confirmación'\n />\n }",
|
|
94
|
+
"import { AlertDialog } from '@imj_media/ui';\nimport { useState } from 'react';\n\nexport default function SizesExample() {\n const [isOpen, setIsOpen] = useState(false);\n \n return (\n <AlertDialog\n size=\"lg\" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\n title='Confirmar acción'\n iconContent={faInfoCircle}\n heading='¿Confirmar?'\n subheading='Este AlertDialog usa un tamaño grande.'\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n onConfirm={() => console.log('Confirmado')}\n successButtonText=\"Aceptar\"\n successButtonColor=\"primary\"\n />\n );\n}"
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "Avatar",
|
|
101
|
+
"path": "src/modules/Avatar",
|
|
102
|
+
"legacy": false,
|
|
103
|
+
"compositionType": 1,
|
|
104
|
+
"exports": [
|
|
105
|
+
{
|
|
106
|
+
"name": "Avatar",
|
|
107
|
+
"kind": "component",
|
|
108
|
+
"description": {
|
|
109
|
+
"primary": "jsdoc",
|
|
110
|
+
"jsdoc": "============================================\nAVATAR COMPONENT - ATOMIC DESIGN\n============================================\nComponente Avatar versátil que sigue principios de Atomic Design.\nActúa como un wrapper que delega la renderización a subcomponentes\nespecializados según el tipo de avatar.\n## Tipos de Avatar\n### 1. People Avatar (type: 'people')\nMuestra una imagen de persona con manejo de errores y fallback automático al icono por defecto\n### 2. Icon Avatar (type: 'icon')\nMuestra un icono del sistema de iconos con temas de color\n### 3. Letter Avatar (type: 'letter')\nMuestra texto (iniciales, números, símbolos) con truncado automático\n## Personalización\nPara modificar colores, tamaños, o agregar nuevos temas:\n@see /constants/index.ts - Tokens de diseño centralizados\n@see /types/index.t",
|
|
111
|
+
"readme": "# Avatar Component\n\nComponente Avatar versátil construido con **Atomic Design** que soporta múltiples tipos: imágenes de personas, iconos y letras/números.\n\n## 📋 Tabla de Contenidos\n\n- [Características](#características)\n- [Tipos de Avatar](#tipos-de-avatar)\n- [Props](#props)\n- [Ejemplos de Uso](#ejemplos-de-uso)\n- [Personalización](#personalización)\n- [Estructura del Componente](#estructura-del-componente)\n\n## ✨ Características\n\n- ✅ **3 tipos de avatar**: People (imagen), Icon (icono), Letter (texto/números)\n- ✅ **Atomic Design**: Estructura modular y mantenible\n- ✅ **6 tamaños**: xxs, xs, sm, md, lg, xl\n- ✅ **11 colores**: blue, red, orange, yellow, lime, green, cyan, azure, violet, magenta, rose\n- ✅ **2 temas**: solid y soft\n- ✅ **Personalización**: Border (stroke) y forma (pill/rounded)\n- ✅ **Performance**: Lazy loading y preload de imágenes\n- ✅ **TypeScript**: Completamente tipado\n- ✅ **Documentación**: Stories completas en Storybook\n\n## 🎯 Tipos de Avatar\n\n### 1. People Avatar (type: 'people')\n\nMuestra una imagen de persona con manejo de errores y fallback automático al icono por defecto.\n\n```tsx\n<Avatar type=\"people\" src=\"https://example.com/avatar.jpg\" alt=\"John Doe\" size=\"md\" />\n```\n\n### 2. Icon Avatar (type: 'icon')\n\nMuestra un icono fijo (UserOutlined).\n\n```tsx\n<Avatar\n type=\"icon\"\n theme=\"solid\" // 'solid' | 'soft'\n color=\"blue\" // 11 colores disponibles\n size=\"md\"\n/>\n```\n\n### 3. Letter Avatar (type: 'letter')\n\nMuestra texto, ideal para iniciales, contadores o indicadores.\n\n```tsx\n// Iniciales\n<Avatar\n type=\"letter\"\n text=\"AB\"\n theme=\"solid\"\n color=\"blue\"\n size=\"md\"\n/>\n\n// Contador estilo Teams\n<Avatar\n type=\"letter\"\n text=\"99+\"\n theme=\"solid\"\n color=\"red\"\n size=\"sm\"\n/>\n\n// Indicador\n<Avatar\n type=\"letter\"\n text=\"+5\"\n theme=\"soft\"\n color=\"green\"\n size=\"md\"\n/>\n```\n\n## 📝 Props\n\n### Props Comunes (todas los tipos)\n\n| Prop | Tipo | Default | Descripción |\n| ---------------",
|
|
112
|
+
"confidence": "medium"
|
|
113
|
+
},
|
|
114
|
+
"examples": []
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"id": "Badge",
|
|
120
|
+
"path": "src/modules/Badge",
|
|
121
|
+
"legacy": false,
|
|
122
|
+
"compositionType": 1,
|
|
123
|
+
"exports": [
|
|
124
|
+
{
|
|
125
|
+
"name": "Badge",
|
|
126
|
+
"kind": "component",
|
|
127
|
+
"description": {
|
|
128
|
+
"primary": "storybook",
|
|
129
|
+
"storybook": "El componente Badge permite mostrar pequeñas notificaciones y contadores. **API preferida:** bloques",
|
|
130
|
+
"jsdoc": "Módulo Badge — insignia contador/estado del design system.\nExporta {@link Badge} para uso desde `@imj_media/ui` o `@/modules/Badge`.\nLas props públicas (`BadgeProps` y sub-interfaces) viven en `@/shared/types/badge`.",
|
|
131
|
+
"readme": "# Badge Component\n\nComponente de insignia/badge versátil y configurable con soporte para diferentes tamaños, colores, temas, iconos, estados de carga y personalización avanzada.\n\n## Uso Básico\n\n```tsx\nimport { Badge } from '@imj_media/ui';\n\n// Badge simple con label\n<Badge label=\"3\" color=\"danger\" />\n\n// Badge tipo dot (sin label)\n<Badge size=\"dot\" color=\"accent\" />\n\n// Badge con icono\n<Badge label=\"Nuevo\" icon=\"StarOutlined\" color=\"success\" />\n```\n\n## Props Principales\n\n### Contenido\n\n- `label?: string | number` - Texto o número del badge (default: `''`)\n- `icon?: IconType | AnyIconDefinition` - Icono del badge (no se muestra en tamaño `dot`)\n\n### Tamaño y Estilo\n\n- `size?: 'dot' | 'sm' | 'md' | 'lg'` - Tamaño del badge (default: `'dot'`)\n- `color?: 'accent' | 'gray' | 'success' | 'warning' | 'danger' | 'info'` - Color del badge (default: `'accent'`)\n- `theme?: 'solid' | 'soft'` - Tema del badge (default: `'solid'`)\n- `stroke?: boolean` - Mostrar borde (default: `false`)\n\n### Estados\n\n- `disabled?: boolean` - Si el badge está deshabilitado (default: `false`)\n- `loading?: boolean` - Mostrar spinner de carga (default: `false`)\n\n### Personalización\n\n- `customColor?: string` - Color personalizado (hex, rgb, etc.)\n- `className?: string` - Clases CSS adicionales\n\n### Iconos Duotone\n\n- `iconDuotonePrimary?: IconFontColor` - Color primario del icono duotone\n- `iconDuotoneSecondary?: IconFontColor` - Color secundario del icono duotone\n- `iconDuotoneOpacityPrimary?: number` - Opacidad primaria (0-1)\n- `iconDuotoneOpacitySecondary?: number` - Opacidad secundaria (0-1)\n\n## Ejemplos\n\n### Badge tipo dot\n\n```tsx\n// Dot simple\n<Badge size=\"dot\" color=\"accent\" />\n\n// Dot con color personalizado\n<Badge size=\"dot\" customColor=\"#ff0000\" />\n```\n\n### Badge con diferentes tamaños\n\n```tsx\n<Badge label=\"1\" size=\"sm\" color=\"danger\" />\n<Badge label=\"12\" size=\"md\" color=\"success\" />\n<Badge label=\"999+\" size=\"lg\" color=\"warning\" />\n```\n\n### Badge con icono\n\n```tsx\n<Badge label=\"Nuevo\" icon=\"St",
|
|
132
|
+
"confidence": "high"
|
|
133
|
+
},
|
|
134
|
+
"examples": [
|
|
135
|
+
"import { Badge } from '@/modules/Badge';\n\nexport default function Example() {\n return (\n <>\n <Badge appearance={{ size: 'dot', color: 'accent' }} />\n <Badge appearance={{ size: 'dot', color: 'gray' }} />\n <Badge appearance={{ size: 'dot', color: 'success' }} />\n <Badge appearance={{ size: 'dot', color: 'warning' }} />\n <Badge appearance={{ size: 'dot', color: 'danger' }} />\n <Badge appearance={{ size: 'dot', color: 'info' }} />\n <Badge appearance={{ size: 'dot' }} state={{ disabled: true }} />\n </>\n )\n}",
|
|
136
|
+
"import { Badge } from '@/modules/Badge';\n\nexport default function Example() {\n return (\n <>\n <Badge appearance={{ size: 'dot', color: 'accent', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'gray', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'success', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'warning', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'danger', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'info', stroke: true }} />\n <Badge appearance={{ size: 'dot', stroke: true }} state={{ disabled: true }} />\n </>\n )\n}",
|
|
137
|
+
"import { Badge } from '@/modules/Badge';\n\nexport default function Example() {\n return (\n <>\n <Badge appearance={{ size: 'dot', color: 'accent', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot', color: 'gray', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot', color: 'success', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot', color: 'warning', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot', color: 'danger', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot', color: 'info', theme: 'soft' }} />\n <Badge appearance={{ size: 'dot' }} state={{ disabled: true }} />\n </>\n )\n}",
|
|
138
|
+
"import { Badge } from '@/modules/Badge';\n\nexport default function Example() {\n return (\n <>\n <Badge appearance={{ size: 'dot', color: 'accent', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'gray', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'success', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'warning', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'danger', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', color: 'info', theme: 'soft', stroke: true }} />\n <Badge appearance={{ size: 'dot', stroke: true }} state={{ disabled: true }} />\n </>\n )\n}",
|
|
139
|
+
"import { Badge } from '@/modules/Badge';\n\nexport default function Example() {\n return (\n <>\n <Badge appearance={{ size: 'sm', color: 'accent' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm', color: 'gray' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm', color: 'success' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm', color: 'warning' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm', color: 'danger' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm', color: 'info' }} text={{ label: '5' }} />\n <Badge appearance={{ size: 'sm' }} text={{ label: '5' }} state={{ disabled: true }} />\n </>\n )\n}"
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"id": "Badges",
|
|
146
|
+
"path": "src/modules/Badges",
|
|
147
|
+
"legacy": false,
|
|
148
|
+
"compositionType": 1,
|
|
149
|
+
"exports": [
|
|
150
|
+
{
|
|
151
|
+
"name": "Badges",
|
|
152
|
+
"kind": "component",
|
|
153
|
+
"description": {
|
|
154
|
+
"primary": "storybook",
|
|
155
|
+
"storybook": "El componente Badges permite crear una lista de badges dinámicos escribiendo texto y presionando Enter. Cada badge puede ser eliminado individualmente.",
|
|
156
|
+
"confidence": "medium"
|
|
157
|
+
},
|
|
158
|
+
"examples": [
|
|
159
|
+
"import { Badges, BadgeItem } from '@imj_media/ui';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [badges, setBadges] = useState<BadgeItem[]>([]);\n\n return (\n <Badges\n label=\"Tags\"\n placeholder=\"Escribe y presiona Enter...\"\n onChange={(event) => setBadges(event.items)}\n />\n );\n}",
|
|
160
|
+
"import { Badges, BadgeItem, BadgesChangeEvent } from '@imj_media/ui';\nimport { useState } from 'react';\n\nconst initialBadges: BadgeItem[] = [\n { id: '1', label: 'React', color: 'accent' },\n { id: '2', label: 'TypeScript', color: 'info' },\n { id: '3', label: 'Tailwind', color: 'success' },\n];\n\nexport default function Example() {\n const [badges, setBadges] = useState<BadgeItem[]>(initialBadges);\n\n const handleChange = (event: BadgesChangeEvent) => {\n setBadges(event.items);\n };\n\n return (\n <Badges\n label=\"Tecnologías\"\n value={initialBadges}\n placeholder=\"Agregar tecnología...\"\n onChange={handleChange}\n />\n );\n}",
|
|
161
|
+
"import { Badges, BadgesChangeEvent } from '@imj_media/ui';\n\n// Simplemente pasa un array de strings\nconst initialTags = ['React', 'TypeScript', 'Tailwind', 'Node.js'];\n\nexport default function Example() {\n return (\n <Badges\n label=\"Tecnologías\"\n value={initialTags}\n placeholder=\"Agregar tecnología...\"\n colorCycle={['accent', 'success', 'info', 'warning']}\n />\n );\n}",
|
|
162
|
+
"import { Badges } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Badges\n label=\"Categorías\"\n placeholder=\"Agregar categoría...\"\n colorCycle={['accent', 'success', 'warning', 'danger', 'info', 'gray']}\n />\n );\n}",
|
|
163
|
+
"import { Badges } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <>\n <Badges label=\"Success\" defaultColor=\"success\" />\n <Badges label=\"Warning\" defaultColor=\"warning\" />\n <Badges label=\"Danger\" defaultColor=\"danger\" />\n <Badges label=\"Info\" defaultColor=\"info\" />\n </>\n );\n}"
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "Breadcrumbs",
|
|
170
|
+
"path": "src/modules/Breadcrumbs",
|
|
171
|
+
"legacy": false,
|
|
172
|
+
"compositionType": 1,
|
|
173
|
+
"exports": [
|
|
174
|
+
{
|
|
175
|
+
"name": "Breadcrumbs",
|
|
176
|
+
"kind": "component",
|
|
177
|
+
"description": {
|
|
178
|
+
"primary": "storybook",
|
|
179
|
+
"storybook": "El componente Breadcrumbs permite mostrar una lista de enlaces que representan la navegación del usuario.",
|
|
180
|
+
"jsdoc": "Breadcrumbs - Componente de migas de pan\nComponente de navegación que muestra la ruta jerárquica actual.\nSoporta truncamiento automático cuando hay muchos items y componente de enlace personalizable.",
|
|
181
|
+
"confidence": "high"
|
|
182
|
+
},
|
|
183
|
+
"examples": [
|
|
184
|
+
"import { Breadcrumbs } from '@imj_media/ui/Breadcrumbs';\n\n const items = [\n { label: 'Home', to: '/' },\n { label: 'About', to: '/about' },\n { label: 'Contact', to: '/contact' },\n { label: 'Gallery', to: '/gallery' },\n { label: 'Blog', to: '/blog' },\n { label: 'History', to: '/history' },\n ];\n\n export default function Example() {\n return (\n <>\n <Breadcrumbs items={items} />\n </>\n )\n }",
|
|
185
|
+
"import { Breadcrumbs } from '@imj_media/ui/Breadcrumbs';\n import { Link } from '@react-router';\n \n const items = [\n { label: 'Home', to: '/' },\n { label: 'About', to: '/about' },\n { label: 'Contact', to: '/contact' },\n { label: 'Gallery', to: '/gallery' },\n { label: 'Blog', to: '/blog' },\n { label: 'History', to: '/history' },\n ];\n\n export default function Example() {\n return (\n <>\n <Breadcrumbs items={items} LinkComponent={Link} />\n </>\n )\n }",
|
|
186
|
+
"import { Breadcrumbs } from '@imj_media/ui/Breadcrumbs';\n\n const items = [\n { label: 'Home', to: '/' },\n { label: 'About', to: '/about' },\n { label: 'Contact', to: '/contact' },\n { label: 'Gallery', to: '/gallery' },\n { label: 'Blog', to: '/blog' },\n { label: 'History', to: '/history' },\n ];\n\n export default function Example() {\n return (\n <>\n <Breadcrumbs items={items} />\n </>\n )\n }",
|
|
187
|
+
"import { Breadcrumbs } from '@imj_media/ui/Breadcrumbs';\n import { Link } from '@react-router';\n \n const items = [\n { label: 'Home', to: '/' },\n { label: 'About', to: '/about' },\n { label: 'Contact', to: '/contact' },\n { label: 'Gallery', to: '/gallery' },\n { label: 'Blog', to: '/blog' },\n { label: 'History', to: '/history' },\n ];\n\n export default function Example() {\n return (\n <>\n <Breadcrumbs items={items} LinkComponent={Link} />\n </>\n )\n }"
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"id": "Button",
|
|
194
|
+
"path": "src/modules/Button",
|
|
195
|
+
"legacy": false,
|
|
196
|
+
"compositionType": 1,
|
|
197
|
+
"exports": [
|
|
198
|
+
{
|
|
199
|
+
"name": "Button",
|
|
200
|
+
"kind": "component",
|
|
201
|
+
"description": {
|
|
202
|
+
"primary": "storybook",
|
|
203
|
+
"storybook": "El componente Button permite a los usuarios realizar acciones y tomar decisiones con un solo toque.",
|
|
204
|
+
"jsdoc": "Button - Componente de botón versátil y configurable\nComponente wrapper que proporciona una API simplificada sobre InnerButton.\nSoporta múltiples temas, colores, tamaños, iconos, badges y tooltips.",
|
|
205
|
+
"readme": "# Button Component\n\nComponente de botón versátil y configurable con múltiples variantes, tamaños, colores y funcionalidades adicionales.\n\n## Estructura\n\n```\nButton/\n├── components/\n│ └── organisms/\n│ └── Button.tsx # Componente principal\n├── stories/\n│ └── Button.stories.tsx # Storybook stories\n└── index.tsx # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Button } from '@imj_media/ui';\n\n// Botón simple\n<Button onClick={() => console.log('clicked')}>\n Hacer clic\n</Button>\n\n// Botón con icono\n<Button icon=\"ImageOutlined\" onClick={handleClick}>\n Subir imagen\n</Button>\n\n// Botón deshabilitado\n<Button disabled onClick={handleClick}>\n No disponible\n</Button>\n```\n\n## Props Principales\n\n### Tamaño y Estilo\n\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón (default: `'sm'`)\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón (default: `'primary'`)\n- `fullWidth?: boolean` - Si es true, ocupa todo el ancho disponible (default: `false`)\n- `rounded?: boolean` - Si es true, bordes redondeados (default: `false`)\n\n### Contenido\n\n- `children?: React.ReactNode` - Contenido del botón\n- `icon?: IconType | AnyIconDefinition` - Icono principal del botón\n- `leftSlot?: React.ReactNode` - Slot izquierdo personalizado\n- `rightSlot?: React.ReactNode` - Slot derecho personalizado\n\n### Funcionalidad\n\n- `onClick?: (e: React.MouseEvent) => void` - Callback al hacer clic\n- `disabled?: boolean` - Si es true, el botón está deshabilitado\n- `clickable?: boolean` - Si es true, el botón es clickeable (default: `true`)\n- `link?: string` - URL para convertir el botón en enlace\n- `target?: '_self' | '_blank' | '_parent' | '_top'` - Target para enlaces (default: `'_self'`)\n\n### Badge\n\n- `badgeColor?: BadgeColor` - Color del badge\n- `badgeLabel?: string` - Texto del badge\n- `badgeTheme?: BadgeTheme` - Tema del badge\n- `badgeSize?: BadgeSize` - Tamaño del badge\n- `badgeIcon?: IconType",
|
|
206
|
+
"confidence": "high"
|
|
207
|
+
},
|
|
208
|
+
"examples": [
|
|
209
|
+
"import { Button } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <Button color=\"primary\">Blue</Button>\n <Button color=\"secondary\">Red</Button>\n <Button color=\"tertiary\">Green</Button>\n <Button color=\"destructive\">Orange</Button>\n <Button color=\"primary\">White</Button>\n </>\n )\n }",
|
|
210
|
+
"import { Button } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <Button color=\"primary\">Blue</Button>\n <Button color=\"secondary\">Red</Button>\n <Button color=\"tertiary\">Green</Button>\n <Button color=\"destructive\">Orange</Button>\n <Button color=\"primary\">White</Button>\n </>\n )\n }",
|
|
211
|
+
"import { Button } from '@imj_media/ui';\nimport { faUser, faImage } from '@fortawesome/pro-solid-svg-icons';\n\nexport default function FullWidthSlotsExample() {\n return (\n <div className=\"ui-flex ui-max-w-2xl ui-flex-col ui-gap-3\">\n <Button\n color=\"primary\"\n size=\"lg\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'center' }}\n leftSlot={faUser}\n rightSlot={faImage}\n >\n Continuar\n </Button>\n </div>\n );\n}",
|
|
212
|
+
"import { Button } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <Button color=\"primary\" tooltip=\"Tooltip\">Blue</Button>\n <Button color=\"secondary\" tooltip=\"Tooltip\">Red</Button>\n <Button color=\"tertiary\" tooltip=\"Tooltip\">Green</Button>\n <Button color=\"destructive\" tooltip=\"Tooltip\">Orange</Button>\n </>\n )\n }",
|
|
213
|
+
"import { Button } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <Button color=\"primary\" tooltip=\"Tooltip\">Blue</Button>\n <Button color=\"secondary\" tooltip=\"Tooltip\">Red</Button>\n <Button color=\"tertiary\" tooltip=\"Tooltip\">Green</Button>\n <Button color=\"destructive\" tooltip=\"Tooltip\">Orange</Button>\n </>\n )\n }"
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": "ButtonGroup",
|
|
220
|
+
"path": "src/modules/ButtonGroup",
|
|
221
|
+
"legacy": false,
|
|
222
|
+
"compositionType": 1,
|
|
223
|
+
"exports": [
|
|
224
|
+
{
|
|
225
|
+
"name": "ButtonGroup",
|
|
226
|
+
"kind": "component",
|
|
227
|
+
"description": {
|
|
228
|
+
"primary": "storybook",
|
|
229
|
+
"storybook": "El componente ButtonGroup permite agrupar múltiples botones con bordes redondeados en los extremos y botones unidos en el centro.",
|
|
230
|
+
"confidence": "medium"
|
|
231
|
+
},
|
|
232
|
+
"examples": [
|
|
233
|
+
"import { ButtonGroup } from '@/modules/ButtonGroup';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n return (\n <>\n <ButtonGroup>\n <Button tooltip=\"Zoom out\" icon=\"Minus2Outlined\" />\n <Button tooltip=\"100%\" clickable={false}>100%</Button>\n <Button tooltip=\"Zoom in\" icon=\"Plus1Outlined\" />\n </ButtonGroup>\n <ButtonGroup>\n <Button color=\"primary\">Primero</Button>\n <Button color=\"primary\">Segundo</Button>\n <Button color=\"primary\">Tercero</Button>\n </ButtonGroup>\n \n <ButtonGroup>\n <Button variant=\"outlined\" color=\"destructive\">Cancelar</Button>\n <Button variant=\"outlined\" color=\"destructive\">Guardar</Button>\n </ButtonGroup>\n \n <ButtonGroup>\n <Button variant=\"outlined\" color=\"secondary\">Aceptar</Button>\n <Button variant=\"outlined\" color=\"secondary\">Rechazar</Button>\n <Button variant=\"outlined\" color=\"secondary\">Pendiente</Button>\n </ButtonGroup>\n </>\n )\n }",
|
|
234
|
+
"<ButtonGroup>\n <Button size=\"sm\" color=\"primary\">Pequeño</Button>\n <Button size=\"sm\" color=\"primary\">Pequeño</Button>\n <Button size=\"sm\" color=\"primary\">Pequeño</Button>\n </ButtonGroup>\n \n <ButtonGroup>\n <Button size=\"lg\" color=\"secondary\">Grande</Button>\n <Button size=\"lg\" color=\"secondary\">Grande</Button>\n <Button size=\"lg\" color=\"secondary\">Grande</Button>\n </ButtonGroup>",
|
|
235
|
+
"<ButtonGroup>\n <Button variant=\"outlined\" color=\"destructive\">Outlined</Button>\n <Button variant=\"outlined\" color=\"destructive\">Outlined</Button>\n <Button variant=\"outlined\" color=\"destructive\">Outlined</Button>\n </ButtonGroup>\n \n <ButtonGroup>\n <Button variant=\"soft\" color=\"secondary\">Soft</Button>\n <Button variant=\"soft\" color=\"secondary\">Soft</Button>\n <Button variant=\"soft\" color=\"secondary\">Soft</Button>\n </ButtonGroup>",
|
|
236
|
+
"<ButtonGroup>\n <Button color=\"primary\" leftSlot=\"TaskOutlined\">Tareas</Button>\n <Button color=\"primary\" leftSlot=\"CalendarOutlined\">Calendario</Button>\n <Button color=\"primary\" leftSlot=\"UserOutlined\">Usuario</Button>\n </ButtonGroup>\n \n <ButtonGroup>\n <Button variant=\"outlined\" color=\"destructive\" leftSlot=\"DeleteOutlined\">Eliminar</Button>\n <Button variant=\"outlined\" color=\"destructive\" leftSlot=\"EditOutlined\">Editar</Button>\n </ButtonGroup>",
|
|
237
|
+
"<ButtonGroup className=\"ui-shadow-04 ui-p-2 ui-bg-gray-50 ui-rounded-lg\">\n <Button color=\"primary\">Con Sombra</Button>\n <Button color=\"primary\">Con Sombra</Button>\n <Button color=\"primary\">Con Sombra</Button>\n </ButtonGroup>\n \n <ButtonGroup className=\"ui-border-2 ui-border-dashed ui-border-blue-300 ui-p-3 ui-rounded-xl\">\n <Button variant=\"outlined\" color=\"primary\">Borde Punteado</Button>\n <Button variant=\"outlined\" color=\"primary\">Borde Punteado</Button>\n </ButtonGroup>"
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"id": "Cards",
|
|
244
|
+
"path": "src/modules/Cards",
|
|
245
|
+
"legacy": false,
|
|
246
|
+
"compositionType": 1,
|
|
247
|
+
"exports": [
|
|
248
|
+
{
|
|
249
|
+
"name": "Cards",
|
|
250
|
+
"kind": "component",
|
|
251
|
+
"description": {
|
|
252
|
+
"primary": "jsdoc",
|
|
253
|
+
"confidence": "low"
|
|
254
|
+
},
|
|
255
|
+
"examples": []
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"id": "CardsGenericas",
|
|
261
|
+
"path": "src/modules/CardsGenericas",
|
|
262
|
+
"legacy": false,
|
|
263
|
+
"compositionType": 1,
|
|
264
|
+
"exports": [
|
|
265
|
+
{
|
|
266
|
+
"name": "CardsGenericas",
|
|
267
|
+
"kind": "component",
|
|
268
|
+
"description": {
|
|
269
|
+
"primary": "jsdoc",
|
|
270
|
+
"jsdoc": "Chevron Font Awesome (pro-regular), centrado por el propio glifo y el flex del botón. */\nconst ChevronFa = styled(FontAwesomeIcon)<{ $open: boolean }>`\n width: 22px;\n height: 22px;\n flex-shrink: 0;\n display: block;\n margin: 0;\n padding: 0;\n color: #fff;\n transform-origin: 50% 50%;\n transition:\n transform 0.5s ease-in-out,\n color 0.3s ease;\n transform: rotate(${({ $open }) => ($open ? '180deg' : '0deg')});\n\n ${({ $open }) => css`\n @media (max-aspect-ratio: 7/10) {\n transform: rotate(${$open ? '270deg' : '90deg'});\n }\n `}\n`;\n\nconst ToggleButton = styled.button<{ $detail: string; $detailColor: string; $bg: string }>`\n position: absolute;\n right: -25px;\n width: 50px;\n height: 50px;\n background: ${({ $detail }) => $detail};\n top: 50%;\n transform: translateY(-",
|
|
271
|
+
"confidence": "medium"
|
|
272
|
+
},
|
|
273
|
+
"examples": []
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"id": "CardsWithAside",
|
|
279
|
+
"path": "src/modules/CardsWithAside",
|
|
280
|
+
"legacy": false,
|
|
281
|
+
"compositionType": 1,
|
|
282
|
+
"exports": [
|
|
283
|
+
{
|
|
284
|
+
"name": "CardsWithAside",
|
|
285
|
+
"kind": "component",
|
|
286
|
+
"description": {
|
|
287
|
+
"primary": "storybook",
|
|
288
|
+
"storybook": "Componente CardsWithAside que muestra contenido inicial con un panel lateral deslizable que contiene tabs con iconos. Permite mostrar contenido adicional al hacer click en los iconos del panel lateral.",
|
|
289
|
+
"confidence": "medium"
|
|
290
|
+
},
|
|
291
|
+
"examples": [
|
|
292
|
+
"<CardsWithAside activeCard={activeCard}>\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Ver información del usuario\" // Tooltip descriptivo\n >\n <UserContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración general\" // Tooltip descriptivo\n >\n <SettingsContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Centro de notificaciones\" // Tooltip descriptivo\n >\n <NotificationsContent />\n </CardsWithAside.TabContent>\n</CardsWithAside>",
|
|
293
|
+
"// Posición global de tooltips (afecta a todos los tabs)\n<CardsWithAside tooltipPosition=\"right\"> // default\n<CardsWithAside tooltipPosition=\"left\">\n<CardsWithAside tooltipPosition=\"top\">\n<CardsWithAside tooltipPosition=\"bottom\">",
|
|
294
|
+
"// La posición global es \"right\" (default), pero cada tab puede sobrescribirla\n<CardsWithAside tooltipPosition=\"right\">\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Usuario\"\n // Sin tooltipPosition, usa la global \"right\"\n >\n ...\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración\"\n tooltipPosition=\"top\" // Sobrescribe la global\n >\n ...\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Notificaciones\"\n tooltipPosition=\"bottom\" // Sobrescribe la global\n >\n ...\n </CardsWithAside.TabContent>\n</CardsWithAside>",
|
|
295
|
+
"// Mostrar tooltips (default)\n<CardsWithAside showTooltips={true}>\n ...\n</CardsWithAside>\n\n// Ocultar tooltips\n<CardsWithAside showTooltips={false}>\n ...\n</CardsWithAside>",
|
|
296
|
+
"<CardsWithAside activeCard={activeCard}>\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Ver información del usuario\" // Tooltip descriptivo\n >\n <UserContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración general\" // Tooltip descriptivo\n >\n <SettingsContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Centro de notificaciones\" // Tooltip descriptivo\n >\n <NotificationsContent />\n </CardsWithAside.TabContent>\n</CardsWithAside>"
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"name": "TabContent",
|
|
301
|
+
"kind": "component",
|
|
302
|
+
"description": {
|
|
303
|
+
"primary": "storybook",
|
|
304
|
+
"storybook": "Componente CardsWithAside que muestra contenido inicial con un panel lateral deslizable que contiene tabs con iconos. Permite mostrar contenido adicional al hacer click en los iconos del panel lateral.",
|
|
305
|
+
"jsdoc": "Componente TabContent para usar dentro de CardsWithAside",
|
|
306
|
+
"confidence": "high"
|
|
307
|
+
},
|
|
308
|
+
"examples": [
|
|
309
|
+
"<CardsWithAside activeCard={activeCard}>\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Ver información del usuario\" // Tooltip descriptivo\n >\n <UserContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración general\" // Tooltip descriptivo\n >\n <SettingsContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Centro de notificaciones\" // Tooltip descriptivo\n >\n <NotificationsContent />\n </CardsWithAside.TabContent>\n</CardsWithAside>",
|
|
310
|
+
"// Posición global de tooltips (afecta a todos los tabs)\n<CardsWithAside tooltipPosition=\"right\"> // default\n<CardsWithAside tooltipPosition=\"left\">\n<CardsWithAside tooltipPosition=\"top\">\n<CardsWithAside tooltipPosition=\"bottom\">",
|
|
311
|
+
"// La posición global es \"right\" (default), pero cada tab puede sobrescribirla\n<CardsWithAside tooltipPosition=\"right\">\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Usuario\"\n // Sin tooltipPosition, usa la global \"right\"\n >\n ...\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración\"\n tooltipPosition=\"top\" // Sobrescribe la global\n >\n ...\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Notificaciones\"\n tooltipPosition=\"bottom\" // Sobrescribe la global\n >\n ...\n </CardsWithAside.TabContent>\n</CardsWithAside>",
|
|
312
|
+
"// Mostrar tooltips (default)\n<CardsWithAside showTooltips={true}>\n ...\n</CardsWithAside>\n\n// Ocultar tooltips\n<CardsWithAside showTooltips={false}>\n ...\n</CardsWithAside>",
|
|
313
|
+
"<CardsWithAside activeCard={activeCard}>\n <CardsWithAside.TabContent\n id=\"user\"\n icon={faUser}\n tooltip=\"Ver información del usuario\" // Tooltip descriptivo\n >\n <UserContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"settings\"\n icon={faCog}\n tooltip=\"Configuración general\" // Tooltip descriptivo\n >\n <SettingsContent />\n </CardsWithAside.TabContent>\n \n <CardsWithAside.TabContent\n id=\"notifications\"\n icon={faBell}\n tooltip=\"Centro de notificaciones\" // Tooltip descriptivo\n >\n <NotificationsContent />\n </CardsWithAside.TabContent>\n</CardsWithAside>"
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"id": "CatalogCard",
|
|
320
|
+
"path": "src/modules/CatalogCard",
|
|
321
|
+
"legacy": false,
|
|
322
|
+
"compositionType": 1,
|
|
323
|
+
"exports": [
|
|
324
|
+
{
|
|
325
|
+
"name": "CatalogCard",
|
|
326
|
+
"kind": "component",
|
|
327
|
+
"description": {
|
|
328
|
+
"primary": "jsdoc",
|
|
329
|
+
"jsdoc": "**CatalogCard** — tarjeta de catálogo / proveedor / usuario (API **cerrada** por props) alineada al archivo Figma\n[Cards](https://www.figma.com/design/3w0SWvV7C5tDKUybsOcgA4/Cards).\nImplementación partida en {@link CatalogCatalogCard}, {@link CatalogSupplierCard} y paneles de menú\n(`catalogCardMenuPanels`) para mantener archivos acotados.\nNo expone slots `media` / `details` / `cta` con ReactNode arbitrario: el organismo compone `Picture`,\n`Icon`, `Tooltip`, `Button`, `Badge`, `Picture`, `Popup` y `List` según props. El menú **…** es lista de acciones\n({@link CatalogCardMenuItem}); los checkboxes de `tags` van en el panel del **CTA principal** (`onPrimaryTagsSelectionChange`).\nFamilia **`user`**: mismo layout que proveedor (~270px), **sin** rating; opcional **`profile.avatarImageSrc`** (o p",
|
|
330
|
+
"confidence": "medium"
|
|
331
|
+
},
|
|
332
|
+
"examples": []
|
|
333
|
+
}
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"id": "Checkbox",
|
|
338
|
+
"path": "src/modules/Checkbox",
|
|
339
|
+
"legacy": false,
|
|
340
|
+
"compositionType": 1,
|
|
341
|
+
"exports": [
|
|
342
|
+
{
|
|
343
|
+
"name": "Checkbox",
|
|
344
|
+
"kind": "component",
|
|
345
|
+
"description": {
|
|
346
|
+
"primary": "storybook",
|
|
347
|
+
"storybook": "Componente base de checkbox basado en los tokens semánticos de Figma.\n\n### Tokens de Figma usados:\n| Token | Valor | Clase Tailwind |\n|---|---|---|\n| \\",
|
|
348
|
+
"jsdoc": "Estado del checkbox (marcado o no) */\n checked: boolean;\n /** Estado indeterminado (parcialmente seleccionado) */\n indeterminate?: boolean;\n /** Handler cuando cambia el estado */\n onChange: (checked: boolean) => void;\n /** Si el checkbox está deshabilitado */\n disabled?: boolean;\n /** Si el checkbox tiene estado de error */\n error?: boolean;\n /** Clases CSS adicionales para el input */\n className?: string;\n /** Hace el checkbox redondo en lugar de cuadrado */\n round?: boolean;\n /** Tamaño del checkbox */\n size?: 'sm' | 'md';\n /** Nombre del input para formularios */\n name?: string;\n /** ID del input */\n id?: string;\n /** Texto del label asociado al checkbox */\n label?: string;\n /** Texto de soporte debajo del label */\n supportingText?: string;\n /** Clases CSS adici",
|
|
349
|
+
"readme": "# Checkbox Component\n\nComponente de checkbox con soporte para estados indeterminados, labels y texto de soporte.\n\n## Uso Básico\n\n```tsx\nimport { Checkbox } from '@imj_media/ui';\n\n// Checkbox simple\n<Checkbox\n checked={isChecked}\n onChange={(checked) => setIsChecked(checked)}\n/>\n\n// Checkbox con label\n<Checkbox\n checked={isChecked}\n onChange={(checked) => setIsChecked(checked)}\n label=\"Acepto los términos y condiciones\"\n/>\n\n// Checkbox con texto de soporte\n<Checkbox\n checked={isChecked}\n onChange={(checked) => setIsChecked(checked)}\n label=\"Suscribirse al newsletter\"\n supportingText=\"Recibirás actualizaciones por correo\"\n/>\n```\n\n## Props\n\n### Props Requeridos\n\n- `checked: boolean` - Estado del checkbox (marcado o no)\n- `onChange: (checked: boolean) => void` - Handler cuando cambia el estado\n\n### Props Opcionales\n\n- `indeterminate?: boolean` - Estado indeterminado (parcialmente seleccionado) (default: `false`)\n- `disabled?: boolean` - Si el checkbox está deshabilitado (default: `false`)\n- `error?: boolean` - Si el checkbox tiene estado de error (default: `false`)\n- `round?: boolean` - Hace el checkbox redondo en lugar de cuadrado (default: `false`)\n- `size?: 'sm' | 'md'` - Tamaño del checkbox (default: `'md'`)\n- `name?: string` - Nombre del input para formularios\n- `id?: string` - ID del input\n- `label?: string` - Texto del label asociado al checkbox\n- `supportingText?: string` - Texto de soporte debajo del label\n- `className?: string` - Clases CSS adicionales para el input\n- `classNameLabel?: string` - Clases CSS adicionales para el contenedor del label\n\n## Ejemplos\n\n### Checkbox con estado indeterminado\n\n```tsx\n<Checkbox\n checked={false}\n indeterminate={true}\n onChange={(checked) => console.log(checked)}\n label=\"Seleccionar todos\"\n/>\n```\n\n### Checkbox deshabilitado\n\n```tsx\n<Checkbox checked={true} disabled={true} onChange={(checked) => {}} label=\"Opción deshabilitada\" />\n```\n\n### Checkbox con error\n\n```tsx\n<Checkbox\n checked={false}\n error={true}\n on",
|
|
350
|
+
"confidence": "high"
|
|
351
|
+
},
|
|
352
|
+
"examples": [
|
|
353
|
+
"import { Checkbox } from '@imj_media/ui'\n\n// Default (unchecked): bg-fill + border-default\n<Checkbox checked={false} onChange={setChecked} />\n\n// Checked: bg-fill-brand + border-transparent (sin borde visible)\n<Checkbox checked={true} onChange={setChecked} />\n\n// Indeterminate: bg-fill-brand + minus SVG\n<Checkbox checked={false} indeterminate onChange={() => {}} />\n\n// Disabled: bg-fill-disabled + border-disabled / bg-fill-brand-disabled\n<Checkbox checked={false} onChange={() => {}} disabled />\n<Checkbox checked={true} onChange={() => {}} disabled />",
|
|
354
|
+
"// Error unchecked: bg-fill + border-danger\n<Checkbox checked={false} onChange={setChecked} error />\n\n// Error checked: bg-fill-brand + border-danger\n<Checkbox checked={true} onChange={setChecked} error />\n\n// Error indeterminate: bg-fill-brand + border-danger\n<Checkbox checked={false} indeterminate onChange={() => {}} error />",
|
|
355
|
+
"// Cuadrado: radius/surface/forms = 2px\n<Checkbox checked={checked} onChange={setChecked} />\n\n// Redondo: rounded-full\n<Checkbox checked={checked} onChange={setChecked} round />",
|
|
356
|
+
"<Checkbox checked={checked} onChange={setChecked} size=\"sm\" />\n<Checkbox checked={checked} onChange={setChecked} size=\"md\" />",
|
|
357
|
+
"// Con label y supporting text\n<Checkbox\n checked={checked}\n onChange={setChecked}\n id=\"terms\"\n label=\"Label\"\n supportingText=\"Supporting text\"\n/>\n\n// Con error\n<Checkbox\n checked={false}\n onChange={setChecked}\n id=\"error-field\"\n label=\"Label\"\n supportingText=\"Supporting text\"\n error\n/>\n\n// Disabled\n<Checkbox\n checked={true}\n onChange={setChecked}\n id=\"disabled-field\"\n label=\"Label\"\n supportingText=\"Supporting text\"\n disabled\n/>"
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"id": "DatePicker",
|
|
364
|
+
"path": "src/modules/DatePicker",
|
|
365
|
+
"legacy": false,
|
|
366
|
+
"compositionType": 1,
|
|
367
|
+
"exports": [
|
|
368
|
+
{
|
|
369
|
+
"name": "DatePicker",
|
|
370
|
+
"kind": "component",
|
|
371
|
+
"description": {
|
|
372
|
+
"primary": "storybook",
|
|
373
|
+
"storybook": "## DatePicker - Selector de Fechas\n\nUn componente completo y flexible para seleccionar fechas individuales o rangos de fechas.\n\n### Características principales:\n- **Modo único**: Selección de una fecha específica\n- **Modo rango**: Selección de un rango de fechas (inicio y fin)\n- **Vistas múltiples**: Días, meses y años\n- **Internacionalización**: Soporte para diferentes idiomas\n- **Personalización**: Estilos y comportamientos configurables\n- **Validación**: Fechas mínimas y máximas\n- **Modos de control**: Controlado y no controlado\n\n### Casos de uso comunes:\n- Formularios de reservas\n- Filtros de fechas\n- Calendarios de eventos\n- Selectores de período",
|
|
374
|
+
"readme": "# DatePicker - Estructura Modular\n\nEste módulo contiene una implementación modular del DatePicker con componentes atómicos, moleculares y orgánicos, junto con hooks personalizados y tipos TypeScript.\n\n## Estructura de Carpetas\n\n```\nDatePicker/\n├── atoms/ # Componentes atómicos (más básicos)\n├── molecules/ # Componentes moleculares (combinan átomos)\n├── organisms/ # Componentes orgánicos (combinan moléculas)\n├── types/ # Definiciones de tipos TypeScript\n├── hooks/ # Hooks personalizados\n├── stories/ # Storybook stories\n└── index.tsx # Componente principal (legacy)\n```\n\n## Componentes Atómicos (`atoms/`)\n\nComponentes más básicos y reutilizables:\n\n- **Day**: Representa un día individual en el calendario\n- **Month**: Representa un mes en la vista de meses\n- **Year**: Representa un año en la vista de años\n- **WeekDay**: Representa los días de la semana\n- **NavigationButton**: Botón de navegación (anterior/siguiente)\n\n## Componentes Moleculares (`molecules/`)\n\nCombinan componentes atómicos para crear funcionalidades más complejas:\n\n- **CalendarHeader**: Header del calendario con navegación\n- **CalendarGrid**: Cuadrícula de días del calendario\n- **MonthGrid**: Cuadrícula de meses\n- **YearGrid**: Cuadrícula de años\n- **DateInput**: Input para la fecha\n\n## Componentes Orgánicos (`organisms/`)\n\nCombinan componentes moleculares para crear funcionalidades completas:\n\n- **Calendar**: Calendario completo con todas las vistas\n- **DatePickerPortal**: Portal del DatePicker con manejo de posicionamiento\n\n## Hooks (`hooks/`)\n\nHooks personalizados para la lógica del DatePicker:\n\n- **useDatePicker**: Hook principal que maneja el estado del DatePicker\n- **useDateRange**: Hook para manejar rangos de fechas\n- **useCalendar**: Hook para la lógica del calendario\n- **useDateInput**: Hook para el manejo del input\n- **usePortal**: Hook para el manejo del portal\n\n## Tipos (`types/`)\n\nDefiniciones de tipos TypeScript organizadas por funcion",
|
|
375
|
+
"confidence": "high"
|
|
376
|
+
},
|
|
377
|
+
"examples": [
|
|
378
|
+
"import { DatePicker } from '@imj_media/ui';\n\n export default function Example() {\n return <DatePicker />\n }",
|
|
379
|
+
"import { DatePicker } from '@imj_media/ui';\n import { useState } from 'react';\n\n export default function Example() {\n const [selectedDate, setSelectedDate] = useState<Date | null>(new Date('2024-07-15'));\n\n return (\n <DatePicker\n selectedDate={selectedDate}\n onDateChange={setSelectedDate}\n />\n );\n }",
|
|
380
|
+
"import { DatePicker } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <DatePicker \n mode=\"range\"\n selectedRange={{\n start: new Date('2024-07-10'),\n end: new Date('2024-07-20'),\n }}\n />\n )\n }",
|
|
381
|
+
"// Caso que antes fallaba (desfase 1 día en zonas UTC−N):\n// selectedRange={{ start: new Date(\"2026-02-01T00:00:00.000Z\"), end: new Date(\"2026-02-28T00:00:00.000Z\") }}\n// Sin normalización: en México (UTC-6) se veía 31/01 - 27/02.\n// Con normalización interna (toLocalDateOnly): se muestra 01/02 - 28/02.",
|
|
382
|
+
"import { DatePicker } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <DatePicker \n minDate={minDate ?? undefined}\n maxDate={maxDate ?? undefined}\n selectedRange={range}\n onRangeChange={setRange}\n />\n )\n}"
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"id": "Drawer",
|
|
389
|
+
"path": "src/modules/Drawer",
|
|
390
|
+
"legacy": false,
|
|
391
|
+
"compositionType": 1,
|
|
392
|
+
"exports": [
|
|
393
|
+
{
|
|
394
|
+
"name": "Drawer",
|
|
395
|
+
"kind": "component",
|
|
396
|
+
"description": {
|
|
397
|
+
"primary": "storybook",
|
|
398
|
+
"storybook": "El componente Drawer permite mostrar contenido en un panel lateral deslizable con diferentes tamaños, posiciones y configuraciones de botones.",
|
|
399
|
+
"jsdoc": "DrawerFooter - Subcomponente de footer para Drawer\n@internal\n/\nconst DrawerFooter = ({ children, className }: DrawerFooterProps) => {\n return (\n <Card.Footer\n className={cn('ui-flex ui-items-center ui-justify-end ui-gap-x-16 ui-p-16', className)}\n >\n {children}\n </Card.Footer>\n );\n};\n\n// Nombre para identificar el componente\nDrawerFooter.displayName = 'DrawerFooter';\n\n// Función auxiliar para extraer el footer de los children\nconst extractFooterFromChildren = (\n children: ReactNode,\n): { content: ReactNode[]; footer: ReactElement | null } => {\n const content: ReactNode[] = [];\n let footer: ReactElement | null = null;\n\n Children.forEach(children, (child) => {\n if (\n isValidElement(child) &&\n (child.type as { displayName?: string })?.displayName === 'Dra",
|
|
400
|
+
"confidence": "high"
|
|
401
|
+
},
|
|
402
|
+
"examples": [
|
|
403
|
+
"import { Drawer } from '@/modules/Drawer';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <Drawer\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Drawer Básico\"\n size=\"md\"\n position=\"right\"\n >\n <p>Contenido del drawer aquí</p>\n </Drawer>\n )\n}",
|
|
404
|
+
"<Drawer\n isOpen={isOpen}\n onClose={handleClose}\n title=\"…\"\n closeButton={{ tooltip: true }}\n>\n …\n</Drawer>",
|
|
405
|
+
"<Drawer size=\"sm\">...</Drawer> // 280px\n<Drawer size=\"md\">...</Drawer> // 400px (default)\n<Drawer size=\"lg\">...</Drawer> // 560px",
|
|
406
|
+
"<Drawer position=\"left\">...</Drawer>\n<Drawer position=\"right\">...</Drawer> // default",
|
|
407
|
+
"// Max-width personalizado\n<Drawer maxWidth=\"600px\">...</Drawer>\n<Drawer maxWidth=\"50%\">...</Drawer>\n\n// Sin max-width (full width)\n<Drawer fullWidth>...</Drawer>\n\n// Adaptar al contenido interno ✨\n<Drawer fitContent>\n <div style={{ width: '350px' }}>\n Contenido con ancho definido\n </div>\n</Drawer>\n\n// Max-width por defecto basado en size\n<Drawer size=\"md\">...</Drawer> // max-width: 400px"
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"id": "Dropdown",
|
|
414
|
+
"path": "src/modules/Dropdown",
|
|
415
|
+
"legacy": false,
|
|
416
|
+
"compositionType": 1,
|
|
417
|
+
"exports": [
|
|
418
|
+
{
|
|
419
|
+
"name": "Dropdown",
|
|
420
|
+
"kind": "component",
|
|
421
|
+
"description": {
|
|
422
|
+
"primary": "storybook",
|
|
423
|
+
"storybook": "**API agrupada:**",
|
|
424
|
+
"jsdoc": "Dropdown - Componente de dropdown/select versátil y configurable\nComponente de dropdown que soporta búsqueda, selección múltiple, diferentes variantes de lista,\nestados controlados/no controlados, y múltiples tipos de opciones (default, checkbox, radio, toggle, user).\n**Ancho del menú:** el panel de la lista usa por defecto el ancho del trigger como `width` y\n`maxWidth` (no supera el campo). `popover.fullWidth` por defecto es `true` (campo a ancho completo\ndel contenedor).\n**Orden en lista:** por defecto (`list.pinSelectedFirst`), la opción seleccionada aparece arriba\nen el panel (salvo listas con `isGroupTitle`). Desactivar con `list={{ pinSelectedFirst: false }}`.",
|
|
425
|
+
"confidence": "high"
|
|
426
|
+
},
|
|
427
|
+
"examples": [
|
|
428
|
+
"import { Dropdown } from '@/modules/Dropdown';\n import { useState } from 'react';\n\n export default function Example() {\n const [value, setValue] = useState('1');\n\n return (\n <Dropdown\n field={{\n label: 'Selecciona una opción',\n placeholder: 'Elige una opción',\n }}\n items={{\n options: [\n { label: 'Opción 1', value: '1' },\n { label: 'Opción 2', value: '2' },\n { label: 'Opción 3', value: '3' },\n ],\n }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n />\n )\n }",
|
|
429
|
+
"const [value, setValue] = useState('1');\n\n <Dropdown\n field={{ label: 'Dropdown con búsqueda', placeholder: 'Busca y selecciona' }}\n menuSearch={{ searchable: true, searchPlaceholder: 'Buscar...' }}\n items={{ options: manyOptions }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n />",
|
|
430
|
+
"const [value, setValue] = useState(-1);\n\n <Dropdown\n field={{ label: 'Dropdown con Opción por Defecto', placeholder: 'Selecciona una opción' }}\n items={{\n options: [\n { label: 'Opción 1', value: '1' },\n { label: 'Opción 2', value: '2' },\n { label: 'Opción 3', value: '3' },\n ],\n defaultOptionSelected: true,\n }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n />",
|
|
431
|
+
"const [value1, setValue1] = useState('');\n const [value2, setValue2] = useState('');\n const [value3, setValue3] = useState('');\n\n const handleValue1Change = createSingleValueHandler(setValue1);\n const handleValue2Change = createSingleValueHandler(setValue2);\n const handleValue3Change = createSingleValueHandler(setValue3);\n\n <div className=\"space-y-4\">\n <Dropdown\n field={{ label: 'Primer dropdown', placeholder: 'Selecciona opción 1' }}\n items={{ options: sampleOptions }}\n values={{ value: value1 }}\n events={{ onValueChange: handleValue1Change }}\n menuSearch={{ searchable: true }}\n />\n <Dropdown\n field={{ label: 'Segundo dropdown', placeholder: 'Selecciona opción 2' }}\n items={{ options: sampleOptions }}\n values={{ value: value2 }}\n events={{ onValueChange: handleValue2Change }}\n />\n <Dropdown\n field={{ label: 'Tercer dropdown', placeholder: 'Selecciona opción 3' }}\n items={{ options: sampleOptions }}\n values={{ value: value3 }}\n events={{ onValueChange: handleValue3Change }}\n slots={{ leftSlot: faSearch }}\n />\n </div>",
|
|
432
|
+
"const [selectedUser, setSelectedUser] = useState('USR001');\n const [selectedProduct, setSelectedProduct] = useState('PROD-A-001');\n\n const handleUserChange = createSingleValueHandler(setSelectedUser);\n const handleProductChange = createSingleValueHandler(setSelectedProduct);\n\n <Dropdown\n field={{ label: 'Seleccionar Usuario', placeholder: 'Elige un usuario' }}\n items={{ options: customOptions, valueName: 'code', idName: 'identifier' }}\n values={{ value: selectedUser }}\n events={{ onValueChange: handleUserChange }}\n menuSearch={{ searchable: true }}\n />\n\n <Dropdown\n field={{ label: 'Seleccionar Producto', placeholder: 'Elige un producto' }}\n items={{ options: productOptions, valueName: 'sku', idName: 'productId' }}\n values={{ value: selectedProduct }}\n events={{ onValueChange: handleProductChange }}\n menuSearch={{ searchable: true }}\n />",
|
|
433
|
+
"<Dropdown\n field={{ label: 'Menú de opciones', placeholder: 'Selecciona una opción' }}\n items={{ options: [/* … */] }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n list={{ listVariant: 'default' }}\n menuSearch={{ searchable: true }}\n/>",
|
|
434
|
+
"<Dropdown\n field={{ label: 'Configuración', placeholder: 'Selecciona una opción' }}\n items={{ options: [/* … */] }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n list={{ listVariant: 'list-default' }}\n menuSearch={{ searchable: true }}\n/>",
|
|
435
|
+
"<Dropdown\n field={{ label: 'Opciones simples', placeholder: 'Selecciona...' }}\n items={{ options: [/* … */] }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n list={{ listVariant: 'list-default' }}\n/>",
|
|
436
|
+
"<Dropdown\n field={{ label: 'Idioma', placeholder: 'Selecciona un idioma' }}\n items={{ options: [/* … */] }}\n values={{ value }}\n events={{ onValueChange: setValue }}\n list={{ listVariant: 'radio' }}\n/>",
|
|
437
|
+
"const [toggles, setToggles] = useState({\n darkMode: false,\n notifications: true,\n sounds: false,\n autoSave: true,\n});\n\nconst toggleOptions = [\n {\n label: 'Modo oscuro',\n value: 'darkMode',\n description: 'Activar el tema oscuro',\n checked: toggles.darkMode,\n },\n {\n label: 'Notificaciones',\n value: 'notifications',\n description: 'Recibir notificaciones push',\n checked: toggles.notifications,\n },\n];\n\n<Dropdown\n field={{ label: 'Preferencias', placeholder: 'Configurar preferencias' }}\n items={{ options: toggleOptions }}\n list={{ listVariant: 'toggle' }}\n events={{\n onToggleChange: (option, checked) => {\n setToggles((prev) => ({ ...prev, [option.value as string]: checked }));\n },\n }}\n/>",
|
|
438
|
+
"import { useState } from 'react';\n\n export default function BasicMultipleSelection() {\n const [selectedValues, setSelectedValues] = useState([]);\n \n const handleValueChange = (value) => {\n if (Array.isArray(value)) {\n setSelectedValues(value);\n }\n };\n\n return (\n <Dropdown\n field={{ label: 'Selección Múltiple', placeholder: 'Selecciona múltiples opciones' }}\n items={{ options: sampleOptions }}\n values={{ value: selectedValues }}\n events={{ onValueChange: handleValueChange }}\n multi={{ multiple: true, selectionSummary: 'tags' }}\n menuSearch={{ searchable: true }}\n />\n );\n }",
|
|
439
|
+
"<Dropdown\n field={{ label: 'Filtros', placeholder: 'Selecciona…' }}\n items={{ options }}\n values={{ value: selectedValues }}\n events={{ onValueChange: setSelectedValues }}\n multi={{\n multiple: true,\n selectionSummary: 'tags',\n tagsOverflow: 'single-line',\n tagsOverflowPopoverTitle: 'Tipos de medio',\n }}\n menuSearch={{ searchable: true }}\n />",
|
|
440
|
+
"import { faShapes } from '@fortawesome/pro-regular-svg-icons';\n import { Dropdown } from '@/modules/Dropdown';\n\n <Dropdown\n field={{ label: 'Tipo de Indoor padre', placeholder: 'Selecciona uno...' }}\n slots={{ leftSlot: faShapes }}\n popover={{ fullWidth: true, popoverZIndex: 1300 }}\n menuSearch={{ searchable: true, searchPlaceholder: 'Buscar...' }}\n items={{ options: opciones }}\n multi={{\n multiple: true,\n selectionSummary: 'tags',\n tagsOverflow: 'single-line',\n tagsOverflowPopoverTitle: 'Tipos InDoor padre',\n tagsOverflowPopoverZIndex: 1300,\n }}\n checkbox={{\n withCheckbox: true,\n checkboxSelectionTone: 'subtle',\n checkboxPosition: 'end',\n checkboxListDensity: 'compact',\n }}\n values={{ value: tiposPadreSeleccionIds }}\n events={{ onValueChange: (v) => { /* ... */ } }}\n />",
|
|
441
|
+
"import { useState } from 'react';\n import { Dropdown } from '@/modules/Dropdown';\n\n const options = [\n { label: 'Bonnie Green', value: '1', avatarUrl: 'https://i.pravatar.cc/32?img=5' },\n // …\n ];\n\n export default function Example() {\n const [selectedValues, setSelectedValues] = useState(['1', '2', '3', '4', '5', '6']);\n\n return (\n <Dropdown\n field={{ label: 'Usuarios', placeholder: 'Buscar...' }}\n items={{ options }}\n values={{ value: selectedValues }}\n events={{ onValueChange: (v) => Array.isArray(v) && setSelectedValues(v) }}\n multi={{\n multiple: true,\n selectionSummary: 'tags',\n tagsOverflow: 'single-line',\n tagsOverflowPopoverTitle: 'Tipos de medio',\n }}\n checkbox={{\n withCheckbox: true,\n checkboxSelectionTone: 'subtle',\n checkboxPosition: 'end',\n checkboxListDensity: 'compact',\n }}\n menuSearch={{ searchable: true, searchPlaceholder: 'Buscar...' }}\n />\n );\n }",
|
|
442
|
+
"<Dropdown\n field={{ label: 'Plazas', placeholder: 'Seleccionar…' }}\n items={{ options }}\n values={{ value: selectedValues }}\n events={{ onValueChange: (v) => Array.isArray(v) && setSelectedValues(v) }}\n multi={{\n multiple: true,\n selectionSummary: 'tags',\n tagsOverflow: 'single-line',\n tagsOverflowPopoverTitle: 'Plazas seleccionadas',\n }}\n list={{\n listVariant: 'search-multi-checkbox',\n searchMultiCheckbox: {\n search: { placeholder: 'Buscar plaza…', show: true },\n header: { id: 'all-plazas', label: 'Todas las plazas' },\n showClearSelection: true,\n },\n }}\n menuSearch={{ searchable: false }}\n />\n {/* Sin buscador en lista: searchMultiCheckbox.search.show: false */}\n {/* Sin botón «Limpiar selección»: searchMultiCheckbox.showClearSelection: false */}"
|
|
443
|
+
]
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"id": "Emoji",
|
|
449
|
+
"path": "src/modules/Emoji",
|
|
450
|
+
"legacy": false,
|
|
451
|
+
"compositionType": 1,
|
|
452
|
+
"exports": [
|
|
453
|
+
{
|
|
454
|
+
"name": "Emoji",
|
|
455
|
+
"kind": "component",
|
|
456
|
+
"description": {
|
|
457
|
+
"primary": "storybook",
|
|
458
|
+
"storybook": "El componente Emoji permite mostrar emojis del sistema con diferentes tamaños y nombres en español.",
|
|
459
|
+
"confidence": "medium"
|
|
460
|
+
},
|
|
461
|
+
"examples": [
|
|
462
|
+
"import { Emoji } from '@/modules/Emoji';\n\n export default function Example() {\n return <Emoji name=\"abeja\" />\n }",
|
|
463
|
+
"// Ejemplo de uso de emojis\n<Emoji name=\"feliz\" size=\"md\" />\n<Emoji name=\"corazon\" size=\"lg\" />\n<Emoji name=\"pizza\" size=\"xl\" />\n\n// Buscar emojis disponibles\nconst emojiName = \"feliz\"; // Usar el nombre exacto del emoji\n\n// Categorías disponibles\nconst categories = {\n emociones: ['feliz', 'triste', 'enojado', ...],\n animales: ['perro', 'gato', 'abeja', ...],\n comida: ['pizza', 'cafe', 'manzana', ...],\n // ... más categorías\n};",
|
|
464
|
+
"import { Emoji } from '@/modules/Emoji';\n\n export default function Example() {\n return <Emoji name=\"abeja\" />\n }",
|
|
465
|
+
"// Ejemplo de uso de emojis\n<Emoji name=\"feliz\" size=\"md\" />\n<Emoji name=\"corazon\" size=\"lg\" />\n<Emoji name=\"pizza\" size=\"xl\" />\n\n// Buscar emojis disponibles\nconst emojiName = \"feliz\"; // Usar el nombre exacto del emoji\n\n// Categorías disponibles\nconst categories = {\n emociones: ['feliz', 'triste', 'enojado', ...],\n animales: ['perro', 'gato', 'abeja', ...],\n comida: ['pizza', 'cafe', 'manzana', ...],\n // ... más categorías\n};"
|
|
466
|
+
]
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"id": "EmojiPicker",
|
|
472
|
+
"path": "src/modules/EmojiPicker",
|
|
473
|
+
"legacy": false,
|
|
474
|
+
"compositionType": 1,
|
|
475
|
+
"exports": [
|
|
476
|
+
{
|
|
477
|
+
"name": "EmojiPicker",
|
|
478
|
+
"kind": "component",
|
|
479
|
+
"description": {
|
|
480
|
+
"primary": "readme",
|
|
481
|
+
"readme": "# EmojiPicker\n\nComponente selector de emojis con categorías, búsqueda y gestión de emojis recientes.\n\n## Características\n\n- ✅ 8 categorías predefinidas de emojis\n- 🔍 Búsqueda de emojis en tiempo real\n- 🕐 Gestión automática de emojis recientes (localStorage)\n- 📱 Diseño responsive y adaptable\n- 🎨 Totalmente personalizable (ancho, alto, etc.)\n- ♿ Accesible (ARIA labels)\n- 🎯 TypeScript completamente tipado\n\n## Categorías\n\nEl componente incluye las siguientes categorías de emojis:\n\n1. **Recientes** - Emojis usados recientemente\n2. **Sonrisas y personas** - Emojis de emociones y expresiones\n3. **Animales** - Emojis de animales y naturaleza\n4. **Comida** - Emojis de comida y bebida\n5. **Deportes** - Emojis de actividades deportivas\n6. **Viajes** - Emojis de viajes y lugares\n7. **Objetos** - Emojis de objetos diversos\n8. **Símbolos** - Emojis de símbolos y formas\n9. **Banderas** - Emojis de banderas de países\n\n## Uso básico\n\n```tsx\nimport { EmojiPicker } from '@imjmedia/ui';\n\nfunction MyComponent() {\n const handleEmojiSelect = (emoji: string) => {\n console.log('Emoji seleccionado:', emoji);\n };\n\n return <EmojiPicker onEmojiSelect={handleEmojiSelect} />;\n}\n```\n\n## Uso con Popup\n\nEl EmojiPicker funciona perfectamente dentro de un Popup:\n\n```tsx\nimport { EmojiPicker, Popup } from '@imjmedia/ui';\nimport { useState } from 'react';\n\nfunction MyComponent() {\n const [selectedEmoji, setSelectedEmoji] = useState('😊');\n\n return (\n <Popup\n label={selectedEmoji}\n position=\"bottom-left\"\n variant=\"outlined\"\n color=\"white\"\n size=\"md\"\n borderRadius=\"md\"\n closeOnClick={true}\n >\n <EmojiPicker onEmojiSelect={setSelectedEmoji} />\n </Popup>\n );\n}\n```\n\n## Props\n\n### EmojiPickerProps\n\n| Prop | Tipo | Default | Descripción |\n| --------------------- | ------------------------- | ------------- | ------------------------------------------- |\n| `onEmojiSelect`",
|
|
482
|
+
"confidence": "low"
|
|
483
|
+
},
|
|
484
|
+
"examples": [
|
|
485
|
+
"const [selectedEmoji, setSelectedEmoji] = useState('')\n\n<EmojiPicker onEmojiSelect={setSelectedEmoji} />",
|
|
486
|
+
"const [selectedEmoji, setSelectedEmoji] = useState('🎉')\n\n<EmojiPicker \n label={selectedEmoji}\n onEmojiSelect={setSelectedEmoji} \n/>",
|
|
487
|
+
"<EmojiPicker \n width={320} \n height={400}\n onEmojiSelect={(emoji) => console.log(emoji)} \n/>",
|
|
488
|
+
"<EmojiPicker \n showSearch={false}\n onEmojiSelect={(emoji) => console.log(emoji)} \n/>",
|
|
489
|
+
"<EmojiPicker \n position=\"bottom-left\"\n onEmojiSelect={(emoji) => console.log(emoji)} \n/>\n\n<EmojiPicker \n position=\"top\"\n onEmojiSelect={(emoji) => console.log(emoji)} \n/>"
|
|
490
|
+
]
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"id": "FileUploader",
|
|
496
|
+
"path": "src/modules/FileUploader",
|
|
497
|
+
"legacy": false,
|
|
498
|
+
"compositionType": 1,
|
|
499
|
+
"exports": [
|
|
500
|
+
{
|
|
501
|
+
"name": "FileUploader",
|
|
502
|
+
"kind": "component",
|
|
503
|
+
"description": {
|
|
504
|
+
"primary": "storybook",
|
|
505
|
+
"storybook": "Zona de carga con restricciones, lista de archivos y eventos. Props agrupadas:",
|
|
506
|
+
"jsdoc": "50 MiB — mismo criterio que el texto por defecto de `dropZone.hint`. */\nconst DEFAULT_MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;\n\nconst DEFAULT_CONSTRAINTS = {\n multiple: true,\n /** Alineado con el hint por defecto (PNG, JPG, CSV, PDF). */\n accept: '.png,.jpg,.jpeg,.csv,.pdf',\n maxFileSizeBytes: DEFAULT_MAX_FILE_SIZE_BYTES,\n} as const;\n\nconst DEFAULT_LIST = {\n rowSize: 'lg' as FileUploadListRowSize,\n};\n\n/**\nCapas de un icono Font Awesome duotone (mapea a `Icon` / `IconFont`).\n/\nexport interface FileUploaderDropZoneIconDuotoneProps {\n primary?: IconFontColor;\n secondary?: IconFontColor;\n opacityPrimary?: number;\n opacitySecondary?: number;\n}\n\n/**\nIcono de la zona discontinua (misma superficie que `Icon`: tamaño, color y duotono).\nSe fusiona con valores por defecto (`faFile`, `xl`, `di",
|
|
507
|
+
"confidence": "high"
|
|
508
|
+
},
|
|
509
|
+
"examples": [
|
|
510
|
+
"<FileUploader\n events={{\n onFilesAccepted: (files) => { /* ... */ },\n onValidationError: (message, file) => { /* ... */ },\n }}\n />\n // Por defecto: accept '.png,.jpg,.jpeg,.csv,.pdf' y maxFileSizeBytes 50 MiB",
|
|
511
|
+
"<FileUploader\n dropZone={{\n error: 'El archivo no tiene un tipo permitido o supera el límite.',\n }}\n />\n // Restricciones por defecto (tipos + 50 MiB) salvo que pases constraints",
|
|
512
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'uploading',\n progress: 35,\n secondsRemaining: 5,\n detailLine: '3.4 Mb | 35%',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n }}\n />",
|
|
513
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'error',\n errorMessage: 'Error al cargar el archivo.',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n onRetryItem: (id) => { /* ... */ },\n }}\n />",
|
|
514
|
+
"<FileUploader\n list={{\n items: [/* ... status: 'complete', progress: 100 */],\n rowSize: 'lg',\n onRemoveItem: (id) => { /* ... */ },\n onDeleteItem: (id) => { /* ... */ },\n }}\n />"
|
|
515
|
+
],
|
|
516
|
+
"props": {
|
|
517
|
+
"groups": {
|
|
518
|
+
"fileUploaderDropZoneIcon": {
|
|
519
|
+
"props": {
|
|
520
|
+
"name": {
|
|
521
|
+
"name": "name",
|
|
522
|
+
"type": "AnyIconDefinition",
|
|
523
|
+
"required": false
|
|
524
|
+
},
|
|
525
|
+
"size": {
|
|
526
|
+
"name": "size",
|
|
527
|
+
"type": "IconFontSize",
|
|
528
|
+
"required": false
|
|
529
|
+
},
|
|
530
|
+
"color": {
|
|
531
|
+
"name": "color",
|
|
532
|
+
"type": "IconFontColor",
|
|
533
|
+
"required": false
|
|
534
|
+
},
|
|
535
|
+
"colorActive": {
|
|
536
|
+
"name": "colorActive",
|
|
537
|
+
"type": "IconFontColor",
|
|
538
|
+
"required": false
|
|
539
|
+
},
|
|
540
|
+
"className": {
|
|
541
|
+
"name": "className",
|
|
542
|
+
"type": "string",
|
|
543
|
+
"required": false
|
|
544
|
+
},
|
|
545
|
+
"Duotono": {
|
|
546
|
+
"name": "Duotono",
|
|
547
|
+
"type": "colores y opacidades por capa. */",
|
|
548
|
+
"required": true
|
|
549
|
+
},
|
|
550
|
+
"duotone": {
|
|
551
|
+
"name": "duotone",
|
|
552
|
+
"type": "FileUploaderDropZoneIconDuotoneProps",
|
|
553
|
+
"required": false
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
"fileUploaderDropZone": {
|
|
558
|
+
"props": {
|
|
559
|
+
"Figma": {
|
|
560
|
+
"name": "Figma",
|
|
561
|
+
"type": "«Arrastra y suelta tus archivos»). */",
|
|
562
|
+
"required": true
|
|
563
|
+
},
|
|
564
|
+
"title": {
|
|
565
|
+
"name": "title",
|
|
566
|
+
"type": "string",
|
|
567
|
+
"required": false
|
|
568
|
+
},
|
|
569
|
+
"hint": {
|
|
570
|
+
"name": "hint",
|
|
571
|
+
"type": "string",
|
|
572
|
+
"required": false
|
|
573
|
+
},
|
|
574
|
+
"selectLabel": {
|
|
575
|
+
"name": "selectLabel",
|
|
576
|
+
"type": "string",
|
|
577
|
+
"required": false
|
|
578
|
+
},
|
|
579
|
+
"error": {
|
|
580
|
+
"name": "error",
|
|
581
|
+
"type": "string | null",
|
|
582
|
+
"required": false
|
|
583
|
+
},
|
|
584
|
+
"icon": {
|
|
585
|
+
"name": "icon",
|
|
586
|
+
"type": "FileUploaderDropZoneIconProps",
|
|
587
|
+
"required": false
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
"fileUploaderConstraints": {
|
|
592
|
+
"props": {
|
|
593
|
+
"defecto": {
|
|
594
|
+
"name": "defecto",
|
|
595
|
+
"type": "50 MiB (mismo mensaje que el hint).",
|
|
596
|
+
"required": true
|
|
597
|
+
},
|
|
598
|
+
"accept": {
|
|
599
|
+
"name": "accept",
|
|
600
|
+
"type": "string",
|
|
601
|
+
"required": false
|
|
602
|
+
},
|
|
603
|
+
"maxFileSizeBytes": {
|
|
604
|
+
"name": "maxFileSizeBytes",
|
|
605
|
+
"type": "number",
|
|
606
|
+
"required": false
|
|
607
|
+
},
|
|
608
|
+
"maxFiles": {
|
|
609
|
+
"name": "maxFiles",
|
|
610
|
+
"type": "number",
|
|
611
|
+
"required": false
|
|
612
|
+
},
|
|
613
|
+
"maxFilesPerBatch": {
|
|
614
|
+
"name": "maxFilesPerBatch",
|
|
615
|
+
"type": "number",
|
|
616
|
+
"required": false
|
|
617
|
+
},
|
|
618
|
+
"multiple": {
|
|
619
|
+
"name": "multiple",
|
|
620
|
+
"type": "boolean",
|
|
621
|
+
"required": false
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
"fileUploaderList": {
|
|
626
|
+
"props": {
|
|
627
|
+
"items": {
|
|
628
|
+
"name": "items",
|
|
629
|
+
"type": "FileUploadListItemData[]",
|
|
630
|
+
"required": false
|
|
631
|
+
},
|
|
632
|
+
"rowSize": {
|
|
633
|
+
"name": "rowSize",
|
|
634
|
+
"type": "FileUploadListRowSize",
|
|
635
|
+
"required": false
|
|
636
|
+
},
|
|
637
|
+
"onRemoveItem": {
|
|
638
|
+
"name": "onRemoveItem",
|
|
639
|
+
"type": "(id: string) => void",
|
|
640
|
+
"required": false
|
|
641
|
+
},
|
|
642
|
+
"onRetryItem": {
|
|
643
|
+
"name": "onRetryItem",
|
|
644
|
+
"type": "(id: string) => void",
|
|
645
|
+
"required": false
|
|
646
|
+
},
|
|
647
|
+
"onDeleteItem": {
|
|
648
|
+
"name": "onDeleteItem",
|
|
649
|
+
"type": "(id: string) => void",
|
|
650
|
+
"required": false
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
"fileUploaderEvents": {
|
|
655
|
+
"props": {
|
|
656
|
+
"onFilesAccepted": {
|
|
657
|
+
"name": "onFilesAccepted",
|
|
658
|
+
"type": "(files: File[]) => void",
|
|
659
|
+
"required": false
|
|
660
|
+
},
|
|
661
|
+
"onValidationError": {
|
|
662
|
+
"name": "onValidationError",
|
|
663
|
+
"type": "(message: string, files: File[]) => void",
|
|
664
|
+
"required": false
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
"deprecatedRoot": [],
|
|
670
|
+
"flat": {
|
|
671
|
+
"className": {
|
|
672
|
+
"name": "className",
|
|
673
|
+
"type": "string",
|
|
674
|
+
"required": false
|
|
675
|
+
},
|
|
676
|
+
"disabled": {
|
|
677
|
+
"name": "disabled",
|
|
678
|
+
"type": "boolean",
|
|
679
|
+
"required": false
|
|
680
|
+
},
|
|
681
|
+
"dropZone": {
|
|
682
|
+
"name": "dropZone",
|
|
683
|
+
"type": "FileUploaderDropZoneProps",
|
|
684
|
+
"required": false,
|
|
685
|
+
"description": "Zona discontinua: copy visible y `error` de la zona."
|
|
686
|
+
},
|
|
687
|
+
"constraints": {
|
|
688
|
+
"name": "constraints",
|
|
689
|
+
"type": "FileUploaderConstraintsProps",
|
|
690
|
+
"required": false,
|
|
691
|
+
"description": "Input nativo y reglas (`accept`, peso, cupo por lote)."
|
|
692
|
+
},
|
|
693
|
+
"list": {
|
|
694
|
+
"name": "list",
|
|
695
|
+
"type": "FileUploaderListProps",
|
|
696
|
+
"required": false,
|
|
697
|
+
"description": "Lista controlada y callbacks por fila (quitar, reintentar, borrar completado)."
|
|
698
|
+
},
|
|
699
|
+
"events": {
|
|
700
|
+
"name": "events",
|
|
701
|
+
"type": "FileUploaderEventsProps",
|
|
702
|
+
"required": false,
|
|
703
|
+
"description": "Emisión tras validación local; no sustituye el estado de cada fila."
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
"name": "FileUploadListItem",
|
|
710
|
+
"kind": "component",
|
|
711
|
+
"description": {
|
|
712
|
+
"primary": "storybook",
|
|
713
|
+
"storybook": "Zona de carga con restricciones, lista de archivos y eventos. Props agrupadas:",
|
|
714
|
+
"jsdoc": "Datos de la fila (nombre, estado, progreso, etc.). */\n item: FileUploadListItemData;\n /** `lg` como fila ancha en Figma; `sm` compacta (sin barra al completar). */\n rowSize?: FileUploadListRowSize;\n /** Eliminar esta entrada (siempre; en error va antes del reintento). */\n onRemove?: (id: string) => void;\n /**\nReintentar subida tras error (red, 5xx, validación remota, etc.).\nSolo en `status === 'error'`: botón con `faArrowsRotate` junto al cierre (X).\n/\n onRetry?: (id: string) => void;\n /** Eliminar archivo completado (papelera). */\n onDelete?: (id: string) => void;\n className?: string;\n}\n\n/**\nFila de estado de carga: icono de tipo, título, detalle, barra solo mientras `uploading`,\ny acciones (cerrar, reintentar, papelera, check en completo) según Figma *Loader*.",
|
|
715
|
+
"confidence": "high"
|
|
716
|
+
},
|
|
717
|
+
"examples": [
|
|
718
|
+
"<FileUploader\n events={{\n onFilesAccepted: (files) => { /* ... */ },\n onValidationError: (message, file) => { /* ... */ },\n }}\n />\n // Por defecto: accept '.png,.jpg,.jpeg,.csv,.pdf' y maxFileSizeBytes 50 MiB",
|
|
719
|
+
"<FileUploader\n dropZone={{\n error: 'El archivo no tiene un tipo permitido o supera el límite.',\n }}\n />\n // Restricciones por defecto (tipos + 50 MiB) salvo que pases constraints",
|
|
720
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'uploading',\n progress: 35,\n secondsRemaining: 5,\n detailLine: '3.4 Mb | 35%',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n }}\n />",
|
|
721
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'error',\n errorMessage: 'Error al cargar el archivo.',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n onRetryItem: (id) => { /* ... */ },\n }}\n />",
|
|
722
|
+
"<FileUploader\n list={{\n items: [/* ... status: 'complete', progress: 100 */],\n rowSize: 'lg',\n onRemoveItem: (id) => { /* ... */ },\n onDeleteItem: (id) => { /* ... */ },\n }}\n />"
|
|
723
|
+
]
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
"name": "FileTypeIcon",
|
|
727
|
+
"kind": "component",
|
|
728
|
+
"description": {
|
|
729
|
+
"primary": "storybook",
|
|
730
|
+
"storybook": "Zona de carga con restricciones, lista de archivos y eventos. Props agrupadas:",
|
|
731
|
+
"jsdoc": "Tipo de archivo (artwork en `assets/icons/<format>.svg`). */\n format: FileUploaderFileFormat;\n /** Tamaño del bloque (Figma: 18 / 24 / 32). Los SVG de origen son 32×32. */\n size?: FileTypeIconSize;\n className?: string;\n}\n\n/**\nIcono de tipo de archivo según Figma `_file types`.\nUsa los vectores en `modules/FileUploader/assets/icons/*.svg` (documento + badge + etiqueta).",
|
|
732
|
+
"confidence": "high"
|
|
733
|
+
},
|
|
734
|
+
"examples": [
|
|
735
|
+
"<FileUploader\n events={{\n onFilesAccepted: (files) => { /* ... */ },\n onValidationError: (message, file) => { /* ... */ },\n }}\n />\n // Por defecto: accept '.png,.jpg,.jpeg,.csv,.pdf' y maxFileSizeBytes 50 MiB",
|
|
736
|
+
"<FileUploader\n dropZone={{\n error: 'El archivo no tiene un tipo permitido o supera el límite.',\n }}\n />\n // Restricciones por defecto (tipos + 50 MiB) salvo que pases constraints",
|
|
737
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'uploading',\n progress: 35,\n secondsRemaining: 5,\n detailLine: '3.4 Mb | 35%',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n }}\n />",
|
|
738
|
+
"<FileUploader\n list={{\n items: [\n {\n id: '1',\n fileName: 'informe.png',\n format: 'png',\n status: 'error',\n errorMessage: 'Error al cargar el archivo.',\n },\n ],\n onRemoveItem: (id) => { /* ... */ },\n onRetryItem: (id) => { /* ... */ },\n }}\n />",
|
|
739
|
+
"<FileUploader\n list={{\n items: [/* ... status: 'complete', progress: 100 */],\n rowSize: 'lg',\n onRemoveItem: (id) => { /* ... */ },\n onDeleteItem: (id) => { /* ... */ },\n }}\n />"
|
|
740
|
+
],
|
|
741
|
+
"props": {
|
|
742
|
+
"groups": {
|
|
743
|
+
"fileTypeIcon": {
|
|
744
|
+
"props": {
|
|
745
|
+
"format": {
|
|
746
|
+
"name": "format",
|
|
747
|
+
"type": "FileUploaderFileFormat",
|
|
748
|
+
"required": true
|
|
749
|
+
},
|
|
750
|
+
"Figma": {
|
|
751
|
+
"name": "Figma",
|
|
752
|
+
"type": "18 / 24 / 32). Los SVG de origen son 32×32. */",
|
|
753
|
+
"required": true
|
|
754
|
+
},
|
|
755
|
+
"size": {
|
|
756
|
+
"name": "size",
|
|
757
|
+
"type": "FileTypeIconSize",
|
|
758
|
+
"required": false
|
|
759
|
+
},
|
|
760
|
+
"className": {
|
|
761
|
+
"name": "className",
|
|
762
|
+
"type": "string",
|
|
763
|
+
"required": false
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
"deprecatedRoot": [],
|
|
769
|
+
"flat": {
|
|
770
|
+
"format": {
|
|
771
|
+
"name": "format",
|
|
772
|
+
"type": "FileUploaderFileFormat",
|
|
773
|
+
"required": true,
|
|
774
|
+
"description": "Tipo de archivo (artwork en `assets/icons/<format>.svg`)."
|
|
775
|
+
},
|
|
776
|
+
"size": {
|
|
777
|
+
"name": "size",
|
|
778
|
+
"type": "FileTypeIconSize",
|
|
779
|
+
"required": false,
|
|
780
|
+
"description": "Tamaño del bloque (Figma: 18 / 24 / 32). Los SVG de origen son 32×32."
|
|
781
|
+
},
|
|
782
|
+
"className": {
|
|
783
|
+
"name": "className",
|
|
784
|
+
"type": "string",
|
|
785
|
+
"required": false
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
]
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"id": "Filters",
|
|
794
|
+
"path": "src/modules/Filters",
|
|
795
|
+
"legacy": false,
|
|
796
|
+
"compositionType": 1,
|
|
797
|
+
"exports": [
|
|
798
|
+
{
|
|
799
|
+
"name": "Filters",
|
|
800
|
+
"kind": "component",
|
|
801
|
+
"description": {
|
|
802
|
+
"primary": "jsdoc",
|
|
803
|
+
"confidence": "low"
|
|
804
|
+
},
|
|
805
|
+
"examples": [
|
|
806
|
+
"import { useState } from 'react';\n import { Filters } from '@imj_media/ui';\n import { faFilter } from '@fortawesome/pro-regular-svg-icons';\n\n const filters = [\n {\n type: 'dropdown',\n label: 'Estado',\n keyName: 'estado',\n placeholder: 'Seleccionar',\n options: [\n { label: 'Activo', value: 'activo' },\n { label: 'Pendiente', value: 'pendiente' },\n ],\n },\n {\n type: 'input',\n label: 'Buscar',\n keyName: 'buscar',\n placeholder: 'Texto…',\n },\n ];\n\n export function Example() {\n const [applied, setApplied] = useState<Record<string, unknown> | null>(null);\n\n return (\n <Filters\n size=\"xs\"\n color=\"secondary\"\n label=\"Filtros\"\n title=\"Refinar resultados\"\n icon={faFilter}\n clearText=\"Borrar filtros\"\n filters={filters}\n onApply={(states) => setApplied(states)}\n onClear={() => setApplied(null)}\n />\n );\n }",
|
|
807
|
+
"import { useState } from 'react';\n import { Filters } from '@imj_media/ui';\n import { faFilter } from '@fortawesome/pro-regular-svg-icons';\n\n const filters = [\n {\n type: 'dropdown',\n label: 'Estado',\n keyName: 'estado',\n placeholder: 'Seleccionar',\n options: [\n { label: 'Activo', value: 'activo' },\n { label: 'Pendiente', value: 'pendiente' },\n ],\n },\n {\n type: 'input',\n label: 'Buscar',\n keyName: 'buscar',\n placeholder: 'Texto…',\n },\n ];\n\n export function Example() {\n const [applied, setApplied] = useState<Record<string, unknown> | null>(null);\n\n return (\n <Filters\n size=\"xs\"\n color=\"secondary\"\n label=\"Filtros\"\n title=\"Refinar resultados\"\n icon={faFilter}\n clearText=\"Borrar filtros\"\n filters={filters}\n onApply={(states) => setApplied(states)}\n onClear={() => setApplied(null)}\n />\n );\n }"
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
]
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
"id": "Ghantt",
|
|
814
|
+
"path": "src/modules/Ghantt",
|
|
815
|
+
"legacy": false,
|
|
816
|
+
"compositionType": 1,
|
|
817
|
+
"exports": [
|
|
818
|
+
{
|
|
819
|
+
"name": "Ghantt",
|
|
820
|
+
"kind": "component",
|
|
821
|
+
"description": {
|
|
822
|
+
"primary": "storybook",
|
|
823
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
824
|
+
"jsdoc": "X del puntero respecto al borde izquierdo del **mismo** elemento cuyo `scrollLeft` define el desplazamiento\n(viewport de cabecera). Si se mide con el padre del track del cuerpo, thead/tbody pueden desalinearse\n(p. ej. scrollbar vertical solo en el cuerpo) y `scrollLeft + x` cae en el inicio del contenido → anclas en ~2015.\n/\nfunction ghanttWheelTimelineViewportClientX(\n scrollViewportEl: HTMLElement | null,\n clientX: number,\n): number {\n const el = scrollViewportEl;\n if (!el) return 0;\n const r = el.getBoundingClientRect();\n const w = el.clientWidth > 0 ? el.clientWidth : r.width;\n return Math.max(0, Math.min(w, clientX - r.left));\n}\n\nconst DEFAULT_APPEARANCE = {\n trackMinHeightPx: 44,\n} as const;\n\nconst DEFAULT_EVENTS = {} as const;\n\n/**\nTabla estándar {@link Table} con **una colu",
|
|
825
|
+
"confidence": "high"
|
|
826
|
+
},
|
|
827
|
+
"examples": [
|
|
828
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
829
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
830
|
+
]
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
"name": "GhanttTimelineHeader",
|
|
834
|
+
"kind": "component",
|
|
835
|
+
"description": {
|
|
836
|
+
"primary": "storybook",
|
|
837
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
838
|
+
"jsdoc": "Nombre accesible del bloque de cabecera (no dibuja una tercera franja: la cabecera son **dos pisos**\nalineados al ancho de la columna).\n/\n title?: string;\n className?: string;\n}\n\n/**\nCabecera de la columna Gantt en **dos pisos** a ancho completo de la columna, alineados con el cuerpo:\n- **Piso 1:** agrupación temporal (meses en vista diaria/semanal, años en vista mensual). En vista **año** no hay piso superior (solo años en el piso inferior).\n- **Piso 2:** etiquetas de cada slot (días, semanas o meses según `timeline.scale`).\nPensado para usarse como `column.header` de la columna `gantt` (el `HeaderCell` la renderiza a ancho\ncompleto sin la fila de acciones de ordenar/filtrar).",
|
|
839
|
+
"confidence": "high"
|
|
840
|
+
},
|
|
841
|
+
"examples": [
|
|
842
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
843
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
844
|
+
]
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
"name": "GhanttConfigProvider",
|
|
848
|
+
"kind": "component",
|
|
849
|
+
"description": {
|
|
850
|
+
"primary": "storybook",
|
|
851
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
852
|
+
"confidence": "medium"
|
|
853
|
+
},
|
|
854
|
+
"examples": [
|
|
855
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
856
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
857
|
+
]
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
"name": "GHANTT_MODIFIER_ZOOM_MIN_SPAN_MS",
|
|
861
|
+
"kind": "component",
|
|
862
|
+
"description": {
|
|
863
|
+
"primary": "storybook",
|
|
864
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
865
|
+
"confidence": "medium"
|
|
866
|
+
},
|
|
867
|
+
"examples": [
|
|
868
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
869
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
870
|
+
]
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"name": "GHANTT_MODIFIER_ZOOM_GLOBAL_START",
|
|
874
|
+
"kind": "component",
|
|
875
|
+
"description": {
|
|
876
|
+
"primary": "storybook",
|
|
877
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
878
|
+
"confidence": "medium"
|
|
879
|
+
},
|
|
880
|
+
"examples": [
|
|
881
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
882
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
883
|
+
]
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
"name": "GHANTT_MODIFIER_ZOOM_HOUR_HALF_MS",
|
|
887
|
+
"kind": "component",
|
|
888
|
+
"description": {
|
|
889
|
+
"primary": "storybook",
|
|
890
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
891
|
+
"confidence": "medium"
|
|
892
|
+
},
|
|
893
|
+
"examples": [
|
|
894
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
895
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
896
|
+
]
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
"name": "GHANTT_MODIFIER_ZOOM_ORDER",
|
|
900
|
+
"kind": "component",
|
|
901
|
+
"description": {
|
|
902
|
+
"primary": "storybook",
|
|
903
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
904
|
+
"confidence": "medium"
|
|
905
|
+
},
|
|
906
|
+
"examples": [
|
|
907
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
908
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
909
|
+
]
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
"name": "GhanttSlotStrip",
|
|
913
|
+
"kind": "component",
|
|
914
|
+
"description": {
|
|
915
|
+
"primary": "storybook",
|
|
916
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
917
|
+
"confidence": "medium"
|
|
918
|
+
},
|
|
919
|
+
"examples": [
|
|
920
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
921
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
922
|
+
]
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
"name": "GHANTT_DENSE_HEADER_MAX_LABELS",
|
|
926
|
+
"kind": "component",
|
|
927
|
+
"description": {
|
|
928
|
+
"primary": "storybook",
|
|
929
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
930
|
+
"confidence": "medium"
|
|
931
|
+
},
|
|
932
|
+
"examples": [
|
|
933
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
934
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
935
|
+
]
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"name": "GHANTT_DENSE_SLOT_GRID_MIN_SLOTS",
|
|
939
|
+
"kind": "component",
|
|
940
|
+
"description": {
|
|
941
|
+
"primary": "storybook",
|
|
942
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
943
|
+
"confidence": "medium"
|
|
944
|
+
},
|
|
945
|
+
"examples": [
|
|
946
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
947
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
948
|
+
]
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
"name": "GHANTT_HOUR_VIRTUAL_MIN_SLOTS",
|
|
952
|
+
"kind": "component",
|
|
953
|
+
"description": {
|
|
954
|
+
"primary": "storybook",
|
|
955
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
956
|
+
"confidence": "medium"
|
|
957
|
+
},
|
|
958
|
+
"examples": [
|
|
959
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
960
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
961
|
+
]
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
"name": "GHANTT_SCROLL_VIRTUAL_MIN_SLOTS",
|
|
965
|
+
"kind": "component",
|
|
966
|
+
"description": {
|
|
967
|
+
"primary": "storybook",
|
|
968
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
969
|
+
"confidence": "medium"
|
|
970
|
+
},
|
|
971
|
+
"examples": [
|
|
972
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
973
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
974
|
+
]
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
"name": "GHANTT_TIMELINE_HEADER_STACK_HEIGHT_PX",
|
|
978
|
+
"kind": "component",
|
|
979
|
+
"description": {
|
|
980
|
+
"primary": "storybook",
|
|
981
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
982
|
+
"confidence": "medium"
|
|
983
|
+
},
|
|
984
|
+
"examples": [
|
|
985
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
986
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
987
|
+
]
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
"name": "GHANTT_DEFAULT_COLUMN_ID",
|
|
991
|
+
"kind": "component",
|
|
992
|
+
"description": {
|
|
993
|
+
"primary": "storybook",
|
|
994
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
995
|
+
"confidence": "medium"
|
|
996
|
+
},
|
|
997
|
+
"examples": [
|
|
998
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
999
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
1000
|
+
]
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
"name": "DEFAULT_GHANTT_COLUMN_MAX_WIDTH_PX",
|
|
1004
|
+
"kind": "component",
|
|
1005
|
+
"description": {
|
|
1006
|
+
"primary": "storybook",
|
|
1007
|
+
"storybook": "Tabla estándar con una columna Gantt. La API voluminosa va en el objeto",
|
|
1008
|
+
"jsdoc": "Ancho máximo por defecto de la columna Gantt (px). Sustituible con `gantt.column.maxWidth` o `timeline.columnMaxWidthPx`.",
|
|
1009
|
+
"confidence": "high"
|
|
1010
|
+
},
|
|
1011
|
+
"examples": [
|
|
1012
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>",
|
|
1013
|
+
"import { Ghantt, GhanttTimelineHeader } from '@/modules/Ghantt';\n\n<Ghantt\n columns={columns}\n rows={rows}\n borderable\n gantt={{\n column: {\n header: <GhanttTimelineHeader title=\"Plan\" />,\n width: 480,\n },\n data: { accessor: (row) => row.plan },\n timeline: { viewStart: '2026-04-01', viewEnd: '2026-04-22', scale: 'day' },\n events: {\n onBarClick: ({ bar, row }) => console.log(bar.id, row.id),\n },\n }}\n/>"
|
|
1014
|
+
]
|
|
1015
|
+
}
|
|
1016
|
+
]
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
"id": "Header",
|
|
1020
|
+
"path": "src/modules/Header",
|
|
1021
|
+
"legacy": false,
|
|
1022
|
+
"compositionType": 1,
|
|
1023
|
+
"exports": [
|
|
1024
|
+
{
|
|
1025
|
+
"name": "Header",
|
|
1026
|
+
"kind": "component",
|
|
1027
|
+
"description": {
|
|
1028
|
+
"primary": "jsdoc",
|
|
1029
|
+
"confidence": "low"
|
|
1030
|
+
},
|
|
1031
|
+
"examples": [
|
|
1032
|
+
"import { Header } from \"@imj_me/ui\";\n\nconst sampleFilters = [\n {\n label: 'Estado',\n value: 'estado',\n options: [\n { label: 'Activo', value: 'activo', icon: faCheck },\n { label: 'Inactivo', value: 'inactivo', icon: faMinus },\n ],\n icon: faFilter,\n placeholder: 'Estado',\n type: 'dropdown',\n },\n {\n label: 'Tipo',\n value: 'tipo',\n options: [\n { label: 'Plantilla', value: 'plantilla', icon: faList },\n { label: 'Tarea', value: 'tarea', icon: faTasks },\n ],\n icon: faFilter,\n placeholder: 'Tipo',\n type: 'dropdown',\n },\n {\n label: 'Tareas',\n value: 'tareas',\n options: [\n { label: 'Todas', value: 'todas', icon: faList },\n { label: 'Completadas', value: 'completadas', icon: faTasks },\n { label: 'Pendientes', value: 'pendientes', icon: faTasks },\n { label: 'Canceladas', value: 'canceladas', icon: faTasks },\n ],\n icon: faFilter,\n placeholder: 'Tareas',\n type: 'multiple',\n },\n {\n label: 'Fecha',\n value: 'fecha',\n type: 'date',\n },\n {\n label: 'Buscar',\n type: 'input',\n placeholder: 'Buscar',\n },\n {\n label: 'Descripción',\n type: 'textarea',\n placeholder: 'Descripción',\n },\n];\n\nfunction Example() {\n return (\n <Header\n title=\"Plantillas\"\n filters={sampleFilters}\n onClear={() => console.log('Filtros limpiados')}\n onApply={(filters) => console.log('Filtros aplicados:', filters)}\n />\n );\n}",
|
|
1033
|
+
"import { Header } from \"@imj_me/ui\";\n\n// Sin filtros - array vacío\nconst noFilters = [];\n\nfunction Example() {\n return (\n <Header\n title=\"Dashboard\"\n icon={faHome}\n showFilters={false}\n filters={noFilters}\n />\n );\n}",
|
|
1034
|
+
"import { Header } from \"@imj_me/ui\";\n\nconst simpleFilters = [\n {\n label: 'Estado',\n type: 'dropdown',\n options: [\n { label: 'Activo', value: 'activo' },\n { label: 'Inactivo', value: 'inactivo' },\n ],\n },\n {\n label: 'Buscar',\n type: 'input',\n placeholder: 'Buscar...',\n },\n];\n\nfunction Example() {\n return (\n <Header\n title=\"Usuarios\"\n icon={faUser}\n showViewMode={false}\n filters={simpleFilters}\n onClear={() => console.log('Filtros limpiados')}\n onApply={(filters) => console.log('Filtros aplicados:', filters)}\n />\n );\n}",
|
|
1035
|
+
"import { Header } from \"@imj_me/ui\";\n\nconst simpleFilters = [\n {\n label: 'Estado',\n type: 'dropdown',\n options: [\n { label: 'Activo', value: 'activo' },\n { label: 'Inactivo', value: 'inactivo' },\n ],\n },\n {\n label: 'Buscar',\n type: 'input',\n placeholder: 'Buscar...',\n },\n];\n\nfunction Example() {\n return (\n <Header\n title=\"Galería\"\n icon={faGrid}\n viewMode=\"grid\"\n filters={simpleFilters}\n onClear={() => console.log('Filtros limpiados')}\n onApply={(filters) => console.log('Filtros aplicados:', filters)}\n />\n );\n}",
|
|
1036
|
+
"import { Header } from \"@imj_me/ui\";\n\nconst simpleFilters = [\n {\n label: 'Estado',\n type: 'dropdown',\n options: [\n { label: 'Activo', value: 'activo' },\n { label: 'Inactivo', value: 'inactivo' },\n ],\n },\n {\n label: 'Buscar',\n type: 'input',\n placeholder: 'Buscar...',\n },\n];\n\nfunction Example() {\n return (\n <Header\n title=\"Configuración\"\n icon={faSliders}\n filters={simpleFilters}\n onClear={() => console.log('Filtros limpiados')}\n onApply={(filters) => console.log('Filtros aplicados:', filters)}\n />\n );\n}"
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
]
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
"id": "Icon",
|
|
1043
|
+
"path": "src/modules/Icon",
|
|
1044
|
+
"legacy": false,
|
|
1045
|
+
"compositionType": 1,
|
|
1046
|
+
"exports": [
|
|
1047
|
+
{
|
|
1048
|
+
"name": "Icon",
|
|
1049
|
+
"kind": "component",
|
|
1050
|
+
"description": {
|
|
1051
|
+
"primary": "storybook",
|
|
1052
|
+
"storybook": "El componente Icon permite mostrar iconos del sistema de diseño con diferentes tamaños y colores.",
|
|
1053
|
+
"readme": "# Icon Component\n\nEl componente `Icon` permite mostrar iconos SVG con diferentes tamaños, colores y variantes.\n\n## Características\n\n- ✅ Soporte para iconos outline y fill\n- ✅ Múltiples tamaños predefinidos\n- ✅ Sistema de colores consistente\n- ✅ Tipado completo con TypeScript\n- ✅ Compatible con Storybook\n\n## Uso Básico\n\n```tsx\nimport { Icon } from '@your-org/ui';\n\nfunction MyComponent() {\n return <Icon name=\"OutlineEyeIcon\" variant=\"outline\" size=\"md\" color=\"primary\" />;\n}\n```\n\n## Props\n\n| Prop | Tipo | Por defecto | Descripción |\n| ----------- | ----------------------------------------------- | ----------- | -------------------------------------- |\n| `name` | `IconType` | - | Nombre del icono a mostrar (requerido) |\n| `variant` | `'outline' \\| 'fill'` | `'outline'` | Variante del icono |\n| `size` | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'xl' \\| '2xl'` | `'md'` | Tamaño del icono |\n| `color` | `IconColor` | `'primary'` | Color del icono |\n| `className` | `string` | - | Clases CSS adicionales |\n| `svgProps` | `React.SVGProps<SVGSVGElement>` | `{}` | Propiedades adicionales del SVG |\n\n## Tamaños\n\n| Tamaño | Píxeles |\n| ------ | ------- |\n| `xs` | 12px |\n| `sm` | 16px |\n| `md` | 20px |\n| `lg` | 24px |\n| `xl` | 32px |\n| `2xl` | 48px |\n\n## Colores Disponibles\n\n- `primary` - Color primario\n- `secondary` - Color secundario\n- `danger` - Color de peligro/error\n- `success` - Color de éxito\n- `warning` - Color de advertencia\n- `info` - Color informativo\n- `alert` - Color de alerta\n\n## Ejemplos\n\n### Iconos Outline\n\n```tsx\n<div className=\"flex gap-4\">\n <Icon name=\"OutlineEyeIcon\" variant=\"outli",
|
|
1054
|
+
"confidence": "high"
|
|
1055
|
+
},
|
|
1056
|
+
"examples": [
|
|
1057
|
+
"import { Icon } from '@/modules/Icon';\n import { faEye } from '@fortawesome/pro-regular-svg-icons';\n\n export default function Example() {\n return <Icon name={faEye} />\n }",
|
|
1058
|
+
"import { Icon } from '@/modules/Icon';\nimport { faHeart, faStar } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function DuotoneExample() {\n return (\n <>\n {/* Colores semánticos */}\n <Icon\n name={faCheckCircle}\n size=\"xl\"\n colorDuotonePrimary=\"success\"\n colorDuotoneSecondary=\"green\"\n opacityDuotonePrimary={1}\n opacityDuotoneSecondary={0.4}\n />\n\n {/* Combinaciones creativas */}\n <Icon\n name={faTrash}\n size=\"xl\"\n colorDuotonePrimary=\"rose\"\n colorDuotoneSecondary=\"magenta\"\n opacityDuotonePrimary={1}\n opacityDuotoneSecondary={0.3}\n />\n\n {/* Diferentes opacidades */}\n <Icon\n name={faPalette}\n size=\"xl\"\n colorDuotonePrimary=\"blue\"\n colorDuotoneSecondary=\"cyan\"\n opacityDuotonePrimary={1}\n opacityDuotoneSecondary={0.6}\n />\n </>\n );\n}",
|
|
1059
|
+
"import { faEye } from '@fortawesome/pro-regular-svg-icons';\n\n<Icon name={faEye} size=\"xs\" color=\"blue\" />\n<Icon name={faEye} size=\"sm\" color=\"blue\" />\n<Icon name={faEye} size=\"md\" color=\"blue\" />\n<Icon name={faEye} size=\"lg\" color=\"blue\" />",
|
|
1060
|
+
"import { faEye } from '@fortawesome/pro-regular-svg-icons';\n\n<Icon name={faEye} size=\"lg\" color=\"blue\" />\n<Icon name={faEye} size=\"lg\" color=\"default\" />\n<Icon name={faEye} size=\"lg\" color=\"red\" />\n<Icon name={faEye} size=\"lg\" color=\"green\" />\n<Icon name={faEye} size=\"lg\" color=\"yellow\" />\n<Icon name={faEye} size=\"lg\" color=\"current\" />\n<Icon name={faEye} size=\"lg\" color=\"brand\" />",
|
|
1061
|
+
"import { faHome, faSearch, faBell, faUser, faCog, faStar } from '@fortawesome/pro-regular-svg-icons';\n\n<Icon name={faHome} size=\"md\" color=\"blue\" />\n<Icon name={faSearch} size=\"md\" color=\"default\" />\n<Icon name={faBell} size=\"md\" color=\"red\" />\n<Icon name={faUser} size=\"md\" color=\"green\" />\n<Icon name={faCog} size=\"md\" color=\"yellow\" />\n<Icon name={faStar} size=\"md\" color=\"blue\" />"
|
|
1062
|
+
]
|
|
1063
|
+
}
|
|
1064
|
+
]
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
"id": "IconFont",
|
|
1068
|
+
"path": "src/modules/IconFont",
|
|
1069
|
+
"legacy": false,
|
|
1070
|
+
"compositionType": 1,
|
|
1071
|
+
"exports": [
|
|
1072
|
+
{
|
|
1073
|
+
"name": "IconFont",
|
|
1074
|
+
"kind": "component",
|
|
1075
|
+
"description": {
|
|
1076
|
+
"primary": "jsdoc",
|
|
1077
|
+
"confidence": "low"
|
|
1078
|
+
},
|
|
1079
|
+
"examples": []
|
|
1080
|
+
}
|
|
1081
|
+
]
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
"id": "InnerButton",
|
|
1085
|
+
"path": "src/modules/InnerButton",
|
|
1086
|
+
"legacy": false,
|
|
1087
|
+
"compositionType": 1,
|
|
1088
|
+
"exports": [
|
|
1089
|
+
{
|
|
1090
|
+
"name": "InnerButton",
|
|
1091
|
+
"kind": "component",
|
|
1092
|
+
"description": {
|
|
1093
|
+
"primary": "storybook",
|
|
1094
|
+
"storybook": "El componente Button permite a los usuarios realizar acciones y tomar decisiones con un solo toque.",
|
|
1095
|
+
"confidence": "medium"
|
|
1096
|
+
},
|
|
1097
|
+
"examples": [
|
|
1098
|
+
"import { InnerButton } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <InnerButton color=\"primary\">Blue</InnerButton>\n <InnerButton color=\"secondary\">Red</InnerButton>\n <InnerButton color=\"tertiary\">Green</InnerButton>\n <InnerButton color=\"destructive\">Orange</InnerButton>\n <InnerButton color=\"primary\">White</InnerButton>\n </>\n )\n }",
|
|
1099
|
+
"import { InnerButton } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <InnerButton color=\"primary\">Blue</InnerButton>\n <InnerButton color=\"secondary\">Red</InnerButton>\n <InnerButton color=\"tertiary\">Green</InnerButton>\n <InnerButton color=\"destructive\">Orange</InnerButton>\n <InnerButton color=\"primary\">White</InnerButton>\n </>\n )\n }",
|
|
1100
|
+
"import { InnerButton } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} />\n <InnerButton color=\"secondary\" icon={faImage} />\n <InnerButton color=\"tertiary\" icon={faImage} />\n <InnerButton color=\"destructive\" icon={faImage} />\n </div>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} pill=\"xs\" />\n <InnerButton color=\"secondary\" icon={faImage} pill=\"xs\" />\n <InnerButton color=\"tertiary\" icon={faImage} pill=\"xs\" />\n <InnerButton color=\"destructive\" icon={faImage} pill=\"xs\" />\n </div>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} pill=\"sm\" />\n <InnerButton color=\"secondary\" icon={faImage} pill=\"sm\" />\n <InnerButton color=\"tertiary\" icon={faImage} pill=\"sm\" />\n <InnerButton color=\"destructive\" icon={faImage} pill=\"sm\" />\n </div>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} pill=\"md\" />\n <InnerButton color=\"secondary\" icon={faImage} pill=\"md\" />\n <InnerButton color=\"tertiary\" icon={faImage} pill=\"md\" />\n <InnerButton color=\"destructive\" icon={faImage} pill=\"md\" />\n </div>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} pill=\"lg\" />\n <InnerButton color=\"secondary\" icon={faImage} pill=\"lg\" />\n <InnerButton color=\"tertiary\" icon={faImage} pill=\"lg\" />\n <InnerButton color=\"destructive\" icon={faImage} pill=\"lg\" />\n </div>\n <div className=\"ui-flex ui-flex-wrap ui-gap-8\">\n <InnerButton color=\"primary\" icon={faImage} pill=\"pill\" />\n <InnerButton color=\"secondary\" icon={faImage} pill=\"pill\" />\n <InnerButton color=\"tertiary\" icon={faImage} pill=\"pill\" />\n <InnerButton color=\"destructive\" icon={faImage} pill=\"pill\" />\n </div>\n </>\n )\n }",
|
|
1101
|
+
"import { InnerButton } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <InnerButton color=\"primary\" tooltip=\"Tooltip\">Blue</InnerButton>\n <InnerButton color=\"secondary\" tooltip=\"Tooltip\">Red</InnerButton>\n <InnerButton color=\"tertiary\" tooltip=\"Tooltip\">Green</InnerButton>\n <InnerButton color=\"destructive\" tooltip=\"Tooltip\">Orange</InnerButton>\n <InnerButton color=\"primary\" tooltip=\"Tooltip\">White</InnerButton>\n </>\n )\n }",
|
|
1102
|
+
"<InnerButton color=\"primary\" theme='solid'>\n Primary\n </InnerButton>"
|
|
1103
|
+
]
|
|
1104
|
+
}
|
|
1105
|
+
]
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
"id": "Input",
|
|
1109
|
+
"path": "src/modules/Input",
|
|
1110
|
+
"legacy": false,
|
|
1111
|
+
"compositionType": 1,
|
|
1112
|
+
"exports": [
|
|
1113
|
+
{
|
|
1114
|
+
"name": "Input",
|
|
1115
|
+
"kind": "component",
|
|
1116
|
+
"description": {
|
|
1117
|
+
"primary": "storybook",
|
|
1118
|
+
"storybook": "Un componente Input personalizable con soporte para slots, estados de error, y estados controlado y no controlado.",
|
|
1119
|
+
"jsdoc": "Input - Componente de campo de entrada versátil y configurable\nComponente de input que soporta estados controlados y no controlados, labels, mensajes de error,\niconos, slots personalizados, tooltips informativos y múltiples tamaños.",
|
|
1120
|
+
"readme": "# Input Component\n\nComponente de campo de entrada versátil y configurable con soporte para labels, mensajes de error, iconos, slots personalizados y tooltips informativos.\n\n## Estructura\n\n```\nInput/\n├── components/\n│ └── Input.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── input.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Input } from '@imj_media/ui';\n\n// Input simple\n<Input\n label=\"Nombre\"\n value={name}\n onValueChange={(value) => setName(value)}\n/>\n\n// Input con placeholder\n<Input\n label=\"Email\"\n placeholder=\"ejemplo@correo.com\"\n value={email}\n onValueChange={(value) => setEmail(value)}\n/>\n```\n\n## Props Principales\n\n### Contenido y Estado\n\n- `value?: string` - Valor del input (controlado)\n- `defaultValue?: string` - Valor por defecto (no controlado)\n- `onValueChange?: (value: string) => void` - Callback cuando cambia el valor\n- `onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void` - Callback nativo del input\n- `placeholder?: string` - Texto de placeholder\n\n### Labels y Mensajes\n\n- `label?: string` - Label del input\n- `error?: string` - Mensaje de error\n- `helperText?: string` - Texto de ayuda adicional\n- `infoTooltip?: string` - Texto del tooltip informativo\n\n### Slots e Iconos\n\n- `leftSlot?: VisualSlotType` - Slot izquierdo (icono, imagen, avatar)\n- `rightSlot?: VisualSlotType` - Slot derecho (icono, imagen, avatar)\n- `extraSlot?: VisualSlotType` - Slot extra (icono, imagen, avatar)\n- `onClickExtraSlot?: () => void` - Callback al hacer clic en el slot extra\n\n### Estilo y Tamaño\n\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del input (default: `'sm'`)\n- `color?: InputColor` - Color del input\n- `fullWidth?: boolean` - Si es true, ocupa todo el ancho disponible (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'sm'`)\n\n### Funcionalidad\n\n- `disabled?: boolea",
|
|
1121
|
+
"confidence": "high"
|
|
1122
|
+
},
|
|
1123
|
+
"examples": [
|
|
1124
|
+
"import { Input } from '@/modules/Input';\n\n export default function Example() {\n return (\n <Input \n label=\"Input Básico\"\n placeholder=\"Escribe algo aquí...\"\n />\n )\n }",
|
|
1125
|
+
"import { Input } from '@/modules/Input';\n\n export default function Example() {\n return (\n <Input \n label=\"Input Básico\"\n placeholder=\"Escribe algo aquí...\"\n />\n )\n }",
|
|
1126
|
+
"<Input \n label=\"Input con Error\"\n error=\"Este campo es requerido\"\n placeholder=\"Campo requerido\"\n />",
|
|
1127
|
+
"<Input \n label=\"Input con Ayuda\"\n helperText=\"Este texto te ayudará a entender qué información ingresar\"\n placeholder=\"Ingresa tu información\"\n />",
|
|
1128
|
+
"<Input \n label=\"Input Deshabilitado\"\n disabled={true}\n value=\"Valor no editable\"\n />"
|
|
1129
|
+
]
|
|
1130
|
+
}
|
|
1131
|
+
]
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"id": "LegacyButton",
|
|
1135
|
+
"path": "src/modules/LegacyButton",
|
|
1136
|
+
"legacy": true,
|
|
1137
|
+
"legacyReason": "Usa iconos SVG legacy; preferir Button + Icon.",
|
|
1138
|
+
"compositionType": 1,
|
|
1139
|
+
"exports": [
|
|
1140
|
+
{
|
|
1141
|
+
"name": "LegacyButton",
|
|
1142
|
+
"kind": "component",
|
|
1143
|
+
"description": {
|
|
1144
|
+
"primary": "jsdoc",
|
|
1145
|
+
"jsdoc": "Botón equivalente a `Button`, pero los slots e iconos usan nombres tipados de `LegacyIcon` (SVG legacy).",
|
|
1146
|
+
"confidence": "medium"
|
|
1147
|
+
},
|
|
1148
|
+
"examples": []
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
"name": "InnerLegacyButton",
|
|
1152
|
+
"kind": "component",
|
|
1153
|
+
"description": {
|
|
1154
|
+
"primary": "jsdoc",
|
|
1155
|
+
"confidence": "low"
|
|
1156
|
+
},
|
|
1157
|
+
"examples": []
|
|
1158
|
+
}
|
|
1159
|
+
]
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"id": "LegacyIcon",
|
|
1163
|
+
"path": "src/modules/LegacyIcon",
|
|
1164
|
+
"legacy": true,
|
|
1165
|
+
"legacyReason": "Set de iconos SVG legacy; preferir Icon / IconFont.",
|
|
1166
|
+
"compositionType": 1,
|
|
1167
|
+
"exports": [
|
|
1168
|
+
{
|
|
1169
|
+
"name": "LegacyIcon",
|
|
1170
|
+
"kind": "component",
|
|
1171
|
+
"description": {
|
|
1172
|
+
"primary": "storybook",
|
|
1173
|
+
"storybook": "Iconos SVG legacy (",
|
|
1174
|
+
"confidence": "medium"
|
|
1175
|
+
},
|
|
1176
|
+
"examples": [
|
|
1177
|
+
"import { LegacyIcon } from '@/modules/LegacyIcon';\n\n<LegacyIcon name=\"HomeOutlined\" size=\"lg\" color=\"brand\" />\n<LegacyIcon name=\"LogoFill\" size=\"md\" color=\"current\" />",
|
|
1178
|
+
"import { LegacyIcon } from '@/modules/LegacyIcon';\n\n<LegacyIcon name=\"HomeOutlined\" size=\"lg\" color=\"brand\" />\n<LegacyIcon name=\"LogoFill\" size=\"md\" color=\"current\" />"
|
|
1179
|
+
]
|
|
1180
|
+
}
|
|
1181
|
+
]
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
"id": "Lightbox",
|
|
1185
|
+
"path": "src/modules/Lightbox",
|
|
1186
|
+
"legacy": false,
|
|
1187
|
+
"compositionType": 1,
|
|
1188
|
+
"exports": [
|
|
1189
|
+
{
|
|
1190
|
+
"name": "Lightbox",
|
|
1191
|
+
"kind": "component",
|
|
1192
|
+
"description": {
|
|
1193
|
+
"primary": "storybook",
|
|
1194
|
+
"storybook": "El componente Lightbox permite visualizar imágenes en pantalla completa con navegación, indicadores y controles.",
|
|
1195
|
+
"confidence": "medium"
|
|
1196
|
+
},
|
|
1197
|
+
"examples": [
|
|
1198
|
+
"import { useState } from 'react'\nimport { Lightbox, ILightboxImage } from '@/modules/Lightbox'\n\nconst images: ILightboxImage[] = [\n {\n id: 1,\n src: 'https://example.com/image1.jpg',\n title: 'Paisaje de Montaña',\n },\n {\n id: 2,\n src: 'https://example.com/image2.jpg',\n title: 'Naturaleza Salvaje',\n },\n]\n\nexport default function Example() {\n const [isOpen, setIsOpen] = useState(false)\n\n return (\n <>\n <button onClick={() => setIsOpen(true)}>\n Abrir Galería\n </button>\n\n <Lightbox\n images={images}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n />\n </>\n )\n}",
|
|
1199
|
+
"<Lightbox\n images={images}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n displayMode=\"square\"\n/>",
|
|
1200
|
+
"const images: ILightboxImage[] = [\n {\n id: 1,\n src: 'https://example.com/image1.jpg',\n // Sin título\n },\n {\n id: 2,\n src: 'https://example.com/image2.jpg',\n },\n]\n\n<Lightbox\n images={images}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n/>",
|
|
1201
|
+
"<Lightbox\n images={images}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n showIndicators={false}\n/>",
|
|
1202
|
+
"<Lightbox\n images={images}\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n showNavigation={false}\n/>"
|
|
1203
|
+
]
|
|
1204
|
+
}
|
|
1205
|
+
]
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
"id": "LinearGraphic",
|
|
1209
|
+
"path": "src/modules/LinearGraphic",
|
|
1210
|
+
"legacy": false,
|
|
1211
|
+
"compositionType": 1,
|
|
1212
|
+
"exports": [
|
|
1213
|
+
{
|
|
1214
|
+
"name": "LinearGraphic",
|
|
1215
|
+
"kind": "component",
|
|
1216
|
+
"description": {
|
|
1217
|
+
"primary": "storybook",
|
|
1218
|
+
"storybook": "El componente LinearGraphic muestra una barra de progreso con múltiples segmentos, cada uno con su propio color y porcentaje. Soporta tooltips en hover para mostrar información detallada.",
|
|
1219
|
+
"jsdoc": "LinearGraphic - Gráfica lineal de barras de progreso múltiples\nMuestra una barra de progreso con múltiples segmentos, cada uno con su propio\ncolor y porcentaje. Soporta tooltips en hover para mostrar información detallada.",
|
|
1220
|
+
"confidence": "high"
|
|
1221
|
+
},
|
|
1222
|
+
"examples": []
|
|
1223
|
+
},
|
|
1224
|
+
{
|
|
1225
|
+
"name": "LinearGraphicSegment",
|
|
1226
|
+
"kind": "component",
|
|
1227
|
+
"description": {
|
|
1228
|
+
"primary": "storybook",
|
|
1229
|
+
"storybook": "El componente LinearGraphic muestra una barra de progreso con múltiples segmentos, cada uno con su propio color y porcentaje. Soporta tooltips en hover para mostrar información detallada.",
|
|
1230
|
+
"jsdoc": "Datos del segmento */\n data: LinearGraphicData;\n /** Índice del segmento */\n index: number;\n /** Ancho del segmento en porcentaje */\n width: number;\n /** Color semántico del segmento */\n color: LinearGraphicColor;\n /** Si es el primer segmento */\n isFirst: boolean;\n /** Si es el último segmento */\n isLast: boolean;\n /** Altura de la barra */\n height: number;\n /** Duración de la transición */\n transitionDuration: number;\n /** Si mostrar tooltip */\n showTooltip: boolean;\n /** Callback cuando se hace hover */\n onHover?: (data: LinearGraphicData, index: number) => void;\n /** Callback cuando se sale del hover */\n onLeave?: (data: LinearGraphicData, index: number) => void;\n}\n\n/**\nSegmento individual de la gráfica lineal\nÁtomo que representa una porción de la barra de progres",
|
|
1231
|
+
"confidence": "high"
|
|
1232
|
+
},
|
|
1233
|
+
"examples": []
|
|
1234
|
+
}
|
|
1235
|
+
]
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
"id": "ListWithDataInHover",
|
|
1239
|
+
"path": "src/modules/ListWithDataInHover",
|
|
1240
|
+
"legacy": false,
|
|
1241
|
+
"compositionType": 1,
|
|
1242
|
+
"exports": [
|
|
1243
|
+
{
|
|
1244
|
+
"name": "ListWithDataInHover",
|
|
1245
|
+
"kind": "component",
|
|
1246
|
+
"description": {
|
|
1247
|
+
"primary": "storybook",
|
|
1248
|
+
"storybook": "El componente ListWithDataInHover muestra una lista de elementos, cada uno con un indicador de color y un nombre. Al hacer hover sobre un elemento, se muestra un tooltip con el porcentaje asociado.",
|
|
1249
|
+
"jsdoc": "ListWithDataInHover - Lista de elementos con tooltips que muestran datos\nMuestra una lista de elementos, cada uno con un indicador de color y un nombre.\nAl hacer hover sobre un elemento, se muestra un tooltip con el porcentaje asociado.",
|
|
1250
|
+
"confidence": "high"
|
|
1251
|
+
},
|
|
1252
|
+
"examples": []
|
|
1253
|
+
}
|
|
1254
|
+
]
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
"id": "Lists",
|
|
1258
|
+
"path": "src/modules/Lists",
|
|
1259
|
+
"legacy": false,
|
|
1260
|
+
"compositionType": 1,
|
|
1261
|
+
"exports": [
|
|
1262
|
+
{
|
|
1263
|
+
"name": "Lists",
|
|
1264
|
+
"kind": "component",
|
|
1265
|
+
"description": {
|
|
1266
|
+
"primary": "storybook",
|
|
1267
|
+
"storybook": "Organismos de lista por variante (",
|
|
1268
|
+
"readme": "# Componentes de Listas\n\nSistema completo de componentes de listas con **13 variantes** (`variant` en `ListBase`), con **DRY**, **SOC**, **Atomic Design** y **TypeScript Discriminated Unions**.\n\n## API agrupada en `ListBase` (recomendada)\n\nLa API organiza datos y callbacks en **bloques** en la medida de lo posible. Si un valor existe en un bloque y también en la raíz del componente, **gana el bloque**.\n\n### Bloques por responsabilidad\n\n| Bloque | Uso |\n| -------------------------- | -------------------------------------------------------------------------------------------------------------- |\n| **`list`** | Datos: `items`, `groups`, `users`, etc. (depende de `variant`) |\n| **`selection`** | Estado de selección: `currentValue`, `selectedValue`, `selectedUserId`, `selectedItem`, `darkMode` (perfil), … |\n| **`events`** | Callbacks (`onItemClick`, `onSelectionChange`, …) |\n| **`labels`** | Textos: `title`, `searchPlaceholder` (users-select), `clearLabel` / `applyLabel`, … |\n| **`profile`** + **`menu`** | Solo `user-profile`: `profile.user` y `menu.items` |\n| **`options`** | Solo `toggle`: p. ej. `enableReordering` |\n| **`content`** | Solo `empty`: p. ej. `icon` |\n| **`search`** | Solo `search-multi-checkbox`: `show`, `placeholder` |\n\n### Ejemplo mínimo (`variant=\"default\"`)\n\n```tsx\nimport { ListBase } from '@/modules/Lists';\n\n<ListBase\n variant=\"defa",
|
|
1269
|
+
"confidence": "high"
|
|
1270
|
+
},
|
|
1271
|
+
"examples": []
|
|
1272
|
+
}
|
|
1273
|
+
]
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
"id": "Logo",
|
|
1277
|
+
"path": "src/modules/Logo",
|
|
1278
|
+
"legacy": false,
|
|
1279
|
+
"compositionType": 1,
|
|
1280
|
+
"exports": [
|
|
1281
|
+
{
|
|
1282
|
+
"name": "Logo",
|
|
1283
|
+
"kind": "component",
|
|
1284
|
+
"description": {
|
|
1285
|
+
"primary": "storybook",
|
|
1286
|
+
"storybook": "El componente Logo permite mostrar el logo del sistema de diseño en diferentes tamaños.",
|
|
1287
|
+
"jsdoc": "Logo - Componente de logo de la aplicación\nRenderiza el logotipo de marca como SVG (`FillLogoIcon`).\nSoporta diferentes tamaños predefinidos.",
|
|
1288
|
+
"confidence": "high"
|
|
1289
|
+
},
|
|
1290
|
+
"examples": [
|
|
1291
|
+
"import { Logo } from '@/modules/Logo';\n\n export default function Example() {\n return <Logo />\n }",
|
|
1292
|
+
"<Logo size=\"sm\" />\n <Logo size=\"md\" />\n <Logo size=\"lg\" />",
|
|
1293
|
+
"<div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Logo size=\"md\" />\n <nav className=\"flex gap-4\">\n <a href=\"#\" className=\"text-gray-600 hover:text-gray-900\">Inicio</a>\n <a href=\"#\" className=\"text-gray-600 hover:text-gray-900\">Productos</a>\n <a href=\"#\" className=\"text-gray-600 hover:text-gray-900\">Servicios</a>\n <a href=\"#\" className=\"text-gray-600 hover:text-gray-900\">Contacto</a>\n </nav>\n </div>\n <div className=\"flex items-center gap-2\">\n <button className=\"px-4 py-2 text-sm bg-blue-500 text-white rounded hover:bg-blue-600\">\n Iniciar Sesión\n </button>\n </div>\n </div>",
|
|
1294
|
+
"<div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Logo size=\"sm\" />\n <p className=\"text-sm text-gray-600\">© 2024 Tu Empresa. Todos los derechos reservados.</p>\n </div>\n <div className=\"flex gap-4\">\n <a href=\"#\" className=\"text-sm text-gray-600 hover:text-gray-900\">Política de Privacidad</a>\n <a href=\"#\" className=\"text-sm text-gray-600 hover:text-gray-900\">Términos de Servicio</a>\n </div>\n </div>",
|
|
1295
|
+
"import { Logo } from '@/modules/Logo';\n\n export default function Example() {\n return <Logo />\n }"
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
"id": "Message",
|
|
1302
|
+
"path": "src/modules/Message",
|
|
1303
|
+
"legacy": true,
|
|
1304
|
+
"legacyReason": "API legada de mensajes; preferir Notification.",
|
|
1305
|
+
"compositionType": 1,
|
|
1306
|
+
"exports": [
|
|
1307
|
+
{
|
|
1308
|
+
"name": "Toaster",
|
|
1309
|
+
"kind": "component",
|
|
1310
|
+
"description": {
|
|
1311
|
+
"primary": "jsdoc",
|
|
1312
|
+
"jsdoc": "Componente que renderiza todos los toasts en un portal",
|
|
1313
|
+
"readme": "# Módulo Message (`@imj_media/ui`)\n\nSuperficie del design system para **mensajes efímeros en pantalla**: toasts (mensajes cortos apilables) y **notificaciones** (tarjetas agrupables por posición y “mazos” `primary` / `secondary` / `auto`). Todo se pinta vía **portal** en `document.body` para no romper el flujo del layout de la app.\n\n## Qué resuelve y cómo se reparte la API\n\n| Concepto | Rol | API imperativa típica | Host React |\n|----------|-----|----------------------|------------|\n| **Toast** | Mensaje temporal apilable (éxito, error, info, warning, genérico). | `toast.*` delega en `messageService` (véase `Message.services.ts`). | `<Toaster />` solo toasts. |\n| **Notificación** | Tarjeta agrupada (`notification.message`, stacks, dismiss por grupo/mazo). | `notification.*` delega en `notificationService`. | `<Notifier />` solo notificaciones. |\n| **`notify`** | **Fachada unificada**: expone métodos de toast **y** de notificación (`notify.message`, `notify.dismissNotificationStack`, etc.) para un solo import en consumidores. | `notify` en `Message.services.ts`. | Cualquiera de los hosts; suele usarse con `<Messaging />` si la app necesita ambos. |\n| **`Messaging`** | Un único portal que monta **toasts y notificaciones** (combina `MessagePositions` + `NotificationPositions`). | Igual que arriba (`toast`, `notification`, `notify`). | `<Messaging />` |\n\n**`Toaster` + `Notifier` vs `Messaging`:** son equivalentes en datos (mismos hooks/servicios); la diferencia es **qué montas en el árbol**. Si solo usas toasts, basta `<Toaster />`. Si solo notificaciones, `<Notifier />`. Si la aplicación mezcla ambos, `<Messaging />` evita duplicar portales. Sin al menos uno de estos componentes en la app, las llamadas imperativas no tienen dónde renderizarse.\n\nPara exports desde el paquete: el barrel del módulo reexporta componentes y la API vía `Message.api.ts` (consumo desde `@imj_media/ui` según el `index` del paquete).\n\n## Estructura de carpetas\n\n```\nMessage/\n├── components/",
|
|
1314
|
+
"confidence": "medium"
|
|
1315
|
+
},
|
|
1316
|
+
"examples": [
|
|
1317
|
+
"import { notify, Messaging, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Messaging />\n <Button onClick={() => notify.success(\"Operación exitosa!\")}>\n Mostrar mensaje\n </Button>\n </div>\n )",
|
|
1318
|
+
"import { notify } from '@imj_media';\n\n // Mensajes básicos\n notify.success(\"Operación completada exitosamente\")\n notify.error(\"Ha ocurrido un error\")\n notify.info(\"Información importante\")\n notify.warning(\"Advertencia: acción requerida\")\n \n // Notificaciones agrupadas (mazos)\n notify.message({ stackGroup: 'secondary', title: 'Mensaje informativo neutro' })\n notify.message({ title: '¡Nueva funcionalidad disponible!' })",
|
|
1319
|
+
"// ✅ Código existente sigue funcionando sin cambios\n import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Toaster />\n <Button onClick={() => toast.success(\"Hello, world!\")}>\n Mostrar toast\n </Button>\n </div>\n )",
|
|
1320
|
+
"import { toast } from '@imj_media';\n\n toast.success('Toast con API legacy');\n toast.error('Error con toast legacy');\n toast.info('Info con toast legacy');",
|
|
1321
|
+
"// ============================================\n // FORMA ANTIGUA (toast)\n // ============================================\n import { toast, Toaster } from '@imj_media';\n \n toast.success(\"Mensaje\")\n toast.error(\"Error\")\n toast.info(\"Info\")\n toast.warning(\"Warning\")\n\n // ============================================\n // FORMA NUEVA (notify) - Recomendada\n // ============================================\n import { notify, Messaging } from '@imj_media';\n \n notify.success(\"Mensaje\")\n notify.error(\"Error\")\n notify.info(\"Info\")\n notify.warning(\"Warning\")\n \n // ✨ Métodos adicionales\n notify.message({ stackGroup: 'secondary', title: 'Mensaje neutro' })\n notify.message({ title: 'Mensaje de marca' })",
|
|
1322
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\",
|
|
1323
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n title: 'Cola única',\n message: 'Todas las intenciones comparten el mazo auto.',\n duration: 8000,\n appearance: { intent: 'informativa' },\n });",
|
|
1324
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n stackGroup: 'primary',\n title: 'Brand',\n message: 'Mazo primary',\n duration: 8000,\n });\n\n notify.message({\n stackGroup: 'secondary',\n title: 'Neutral',\n message: 'Mazo secondary',\n duration: 8000,\n });",
|
|
1325
|
+
"import { notification } from '@imj_media';\n\n notification.message({ title: 'Encola en auto' });\n notification.dismissStack('auto');\n notification.dismissStack('primary');\n notification.dismissStack('secondary');",
|
|
1326
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\`notification\\`)\n notify.message({\n title: 'Título corto',\n message: 'Cuerpo por defecto',\n duration: 10000,\n stackGroup: 'secondary', // u omitir → mazo \\`auto\\`\n appearance: { intent: 'preventiva', variant: 'outlined' },\n content: { title: 'Título corto', kind: 'default', description: 'Texto largo…' },\n meta: { presentation: 'popup' },\n events: { onClose: () => {} },\n });",
|
|
1327
|
+
"import { notify, Messaging } from '@imj_media';\n\n // En la app: <Messaging />\n notify.message({\n title: 'Aviso',\n message: 'Texto breve con la apariencia por defecto del sistema.',\n duration: 8000,\n // Equivale a appearance: { intent: 'informativa' } (valor por defecto del componente Notification)\n });",
|
|
1328
|
+
"import { notify } from '@imj_media';\n\n // Mismo tipo: stack compartido (máx. stackMax, por defecto 3)\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 3' }) // Contador en la frontal\n\n // Configurar tamaño del stack (opcional)\n notify.configureNotification({ stackMax: 5 })\n\n // stackGroup 'secondary' usa otro mazo\n notify.message({ stackGroup: 'secondary', title: 'Recordatorio' })\n notify.message({ stackGroup: 'secondary', title: 'Otro recordatorio' })",
|
|
1329
|
+
"import { notify } from '@imj_media';\n\n // Mismo mazo primary: cada encolado con título y mensaje distintos\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n subtitle: 'Hora 14:05:12',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // En la app: setInterval o scheduler que encole copy nuevo cada N ms\n // notify.message({ stackGroup: 'primary', title: '…', message: '…' });",
|
|
1330
|
+
"import { notify } from '@imj_media';\n\n // Una notificación en el mazo (sin pie de apilado)\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // Dos en el mismo mazo: la frontal muestra leyenda personalizada\n notify.message({\n stackGroup: 'primary',\n title: 'Aviso · #2',\n message: 'Hay cambios pendientes. (seq 2)',\n });\n notify.message({\n stackGroup: 'primary',\n title: 'Alerta · #3',\n message: 'La cola se ha actualizado. (seq 3)',\n stackSummaryLegend: 'Tienes 8 mensajes sin leer',\n });",
|
|
1331
|
+
"// Cada nueva notificación reinicia el timer\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' }) // Timer: 5s\n // Después de 2s...\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' }) // Timer: 5s (reiniciado)"
|
|
1332
|
+
]
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"name": "Notifier",
|
|
1336
|
+
"kind": "component",
|
|
1337
|
+
"description": {
|
|
1338
|
+
"primary": "jsdoc",
|
|
1339
|
+
"jsdoc": "Componente que renderiza todas las notificaciones en un portal",
|
|
1340
|
+
"readme": "# Módulo Message (`@imj_media/ui`)\n\nSuperficie del design system para **mensajes efímeros en pantalla**: toasts (mensajes cortos apilables) y **notificaciones** (tarjetas agrupables por posición y “mazos” `primary` / `secondary` / `auto`). Todo se pinta vía **portal** en `document.body` para no romper el flujo del layout de la app.\n\n## Qué resuelve y cómo se reparte la API\n\n| Concepto | Rol | API imperativa típica | Host React |\n|----------|-----|----------------------|------------|\n| **Toast** | Mensaje temporal apilable (éxito, error, info, warning, genérico). | `toast.*` delega en `messageService` (véase `Message.services.ts`). | `<Toaster />` solo toasts. |\n| **Notificación** | Tarjeta agrupada (`notification.message`, stacks, dismiss por grupo/mazo). | `notification.*` delega en `notificationService`. | `<Notifier />` solo notificaciones. |\n| **`notify`** | **Fachada unificada**: expone métodos de toast **y** de notificación (`notify.message`, `notify.dismissNotificationStack`, etc.) para un solo import en consumidores. | `notify` en `Message.services.ts`. | Cualquiera de los hosts; suele usarse con `<Messaging />` si la app necesita ambos. |\n| **`Messaging`** | Un único portal que monta **toasts y notificaciones** (combina `MessagePositions` + `NotificationPositions`). | Igual que arriba (`toast`, `notification`, `notify`). | `<Messaging />` |\n\n**`Toaster` + `Notifier` vs `Messaging`:** son equivalentes en datos (mismos hooks/servicios); la diferencia es **qué montas en el árbol**. Si solo usas toasts, basta `<Toaster />`. Si solo notificaciones, `<Notifier />`. Si la aplicación mezcla ambos, `<Messaging />` evita duplicar portales. Sin al menos uno de estos componentes en la app, las llamadas imperativas no tienen dónde renderizarse.\n\nPara exports desde el paquete: el barrel del módulo reexporta componentes y la API vía `Message.api.ts` (consumo desde `@imj_media/ui` según el `index` del paquete).\n\n## Estructura de carpetas\n\n```\nMessage/\n├── components/",
|
|
1341
|
+
"confidence": "medium"
|
|
1342
|
+
},
|
|
1343
|
+
"examples": [
|
|
1344
|
+
"import { notify, Messaging, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Messaging />\n <Button onClick={() => notify.success(\"Operación exitosa!\")}>\n Mostrar mensaje\n </Button>\n </div>\n )",
|
|
1345
|
+
"import { notify } from '@imj_media';\n\n // Mensajes básicos\n notify.success(\"Operación completada exitosamente\")\n notify.error(\"Ha ocurrido un error\")\n notify.info(\"Información importante\")\n notify.warning(\"Advertencia: acción requerida\")\n \n // Notificaciones agrupadas (mazos)\n notify.message({ stackGroup: 'secondary', title: 'Mensaje informativo neutro' })\n notify.message({ title: '¡Nueva funcionalidad disponible!' })",
|
|
1346
|
+
"// ✅ Código existente sigue funcionando sin cambios\n import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Toaster />\n <Button onClick={() => toast.success(\"Hello, world!\")}>\n Mostrar toast\n </Button>\n </div>\n )",
|
|
1347
|
+
"import { toast } from '@imj_media';\n\n toast.success('Toast con API legacy');\n toast.error('Error con toast legacy');\n toast.info('Info con toast legacy');",
|
|
1348
|
+
"// ============================================\n // FORMA ANTIGUA (toast)\n // ============================================\n import { toast, Toaster } from '@imj_media';\n \n toast.success(\"Mensaje\")\n toast.error(\"Error\")\n toast.info(\"Info\")\n toast.warning(\"Warning\")\n\n // ============================================\n // FORMA NUEVA (notify) - Recomendada\n // ============================================\n import { notify, Messaging } from '@imj_media';\n \n notify.success(\"Mensaje\")\n notify.error(\"Error\")\n notify.info(\"Info\")\n notify.warning(\"Warning\")\n \n // ✨ Métodos adicionales\n notify.message({ stackGroup: 'secondary', title: 'Mensaje neutro' })\n notify.message({ title: 'Mensaje de marca' })",
|
|
1349
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\",
|
|
1350
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n title: 'Cola única',\n message: 'Todas las intenciones comparten el mazo auto.',\n duration: 8000,\n appearance: { intent: 'informativa' },\n });",
|
|
1351
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n stackGroup: 'primary',\n title: 'Brand',\n message: 'Mazo primary',\n duration: 8000,\n });\n\n notify.message({\n stackGroup: 'secondary',\n title: 'Neutral',\n message: 'Mazo secondary',\n duration: 8000,\n });",
|
|
1352
|
+
"import { notification } from '@imj_media';\n\n notification.message({ title: 'Encola en auto' });\n notification.dismissStack('auto');\n notification.dismissStack('primary');\n notification.dismissStack('secondary');",
|
|
1353
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\`notification\\`)\n notify.message({\n title: 'Título corto',\n message: 'Cuerpo por defecto',\n duration: 10000,\n stackGroup: 'secondary', // u omitir → mazo \\`auto\\`\n appearance: { intent: 'preventiva', variant: 'outlined' },\n content: { title: 'Título corto', kind: 'default', description: 'Texto largo…' },\n meta: { presentation: 'popup' },\n events: { onClose: () => {} },\n });",
|
|
1354
|
+
"import { notify, Messaging } from '@imj_media';\n\n // En la app: <Messaging />\n notify.message({\n title: 'Aviso',\n message: 'Texto breve con la apariencia por defecto del sistema.',\n duration: 8000,\n // Equivale a appearance: { intent: 'informativa' } (valor por defecto del componente Notification)\n });",
|
|
1355
|
+
"import { notify } from '@imj_media';\n\n // Mismo tipo: stack compartido (máx. stackMax, por defecto 3)\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 3' }) // Contador en la frontal\n\n // Configurar tamaño del stack (opcional)\n notify.configureNotification({ stackMax: 5 })\n\n // stackGroup 'secondary' usa otro mazo\n notify.message({ stackGroup: 'secondary', title: 'Recordatorio' })\n notify.message({ stackGroup: 'secondary', title: 'Otro recordatorio' })",
|
|
1356
|
+
"import { notify } from '@imj_media';\n\n // Mismo mazo primary: cada encolado con título y mensaje distintos\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n subtitle: 'Hora 14:05:12',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // En la app: setInterval o scheduler que encole copy nuevo cada N ms\n // notify.message({ stackGroup: 'primary', title: '…', message: '…' });",
|
|
1357
|
+
"import { notify } from '@imj_media';\n\n // Una notificación en el mazo (sin pie de apilado)\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // Dos en el mismo mazo: la frontal muestra leyenda personalizada\n notify.message({\n stackGroup: 'primary',\n title: 'Aviso · #2',\n message: 'Hay cambios pendientes. (seq 2)',\n });\n notify.message({\n stackGroup: 'primary',\n title: 'Alerta · #3',\n message: 'La cola se ha actualizado. (seq 3)',\n stackSummaryLegend: 'Tienes 8 mensajes sin leer',\n });",
|
|
1358
|
+
"// Cada nueva notificación reinicia el timer\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' }) // Timer: 5s\n // Después de 2s...\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' }) // Timer: 5s (reiniciado)"
|
|
1359
|
+
]
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
"name": "Messaging",
|
|
1363
|
+
"kind": "component",
|
|
1364
|
+
"description": {
|
|
1365
|
+
"primary": "jsdoc",
|
|
1366
|
+
"jsdoc": "Componente unificado que renderiza tanto toasts como notificaciones",
|
|
1367
|
+
"readme": "# Módulo Message (`@imj_media/ui`)\n\nSuperficie del design system para **mensajes efímeros en pantalla**: toasts (mensajes cortos apilables) y **notificaciones** (tarjetas agrupables por posición y “mazos” `primary` / `secondary` / `auto`). Todo se pinta vía **portal** en `document.body` para no romper el flujo del layout de la app.\n\n## Qué resuelve y cómo se reparte la API\n\n| Concepto | Rol | API imperativa típica | Host React |\n|----------|-----|----------------------|------------|\n| **Toast** | Mensaje temporal apilable (éxito, error, info, warning, genérico). | `toast.*` delega en `messageService` (véase `Message.services.ts`). | `<Toaster />` solo toasts. |\n| **Notificación** | Tarjeta agrupada (`notification.message`, stacks, dismiss por grupo/mazo). | `notification.*` delega en `notificationService`. | `<Notifier />` solo notificaciones. |\n| **`notify`** | **Fachada unificada**: expone métodos de toast **y** de notificación (`notify.message`, `notify.dismissNotificationStack`, etc.) para un solo import en consumidores. | `notify` en `Message.services.ts`. | Cualquiera de los hosts; suele usarse con `<Messaging />` si la app necesita ambos. |\n| **`Messaging`** | Un único portal que monta **toasts y notificaciones** (combina `MessagePositions` + `NotificationPositions`). | Igual que arriba (`toast`, `notification`, `notify`). | `<Messaging />` |\n\n**`Toaster` + `Notifier` vs `Messaging`:** son equivalentes en datos (mismos hooks/servicios); la diferencia es **qué montas en el árbol**. Si solo usas toasts, basta `<Toaster />`. Si solo notificaciones, `<Notifier />`. Si la aplicación mezcla ambos, `<Messaging />` evita duplicar portales. Sin al menos uno de estos componentes en la app, las llamadas imperativas no tienen dónde renderizarse.\n\nPara exports desde el paquete: el barrel del módulo reexporta componentes y la API vía `Message.api.ts` (consumo desde `@imj_media/ui` según el `index` del paquete).\n\n## Estructura de carpetas\n\n```\nMessage/\n├── components/",
|
|
1368
|
+
"confidence": "medium"
|
|
1369
|
+
},
|
|
1370
|
+
"examples": [
|
|
1371
|
+
"import { notify, Messaging, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Messaging />\n <Button onClick={() => notify.success(\"Operación exitosa!\")}>\n Mostrar mensaje\n </Button>\n </div>\n )",
|
|
1372
|
+
"import { notify } from '@imj_media';\n\n // Mensajes básicos\n notify.success(\"Operación completada exitosamente\")\n notify.error(\"Ha ocurrido un error\")\n notify.info(\"Información importante\")\n notify.warning(\"Advertencia: acción requerida\")\n \n // Notificaciones agrupadas (mazos)\n notify.message({ stackGroup: 'secondary', title: 'Mensaje informativo neutro' })\n notify.message({ title: '¡Nueva funcionalidad disponible!' })",
|
|
1373
|
+
"// ✅ Código existente sigue funcionando sin cambios\n import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Toaster />\n <Button onClick={() => toast.success(\"Hello, world!\")}>\n Mostrar toast\n </Button>\n </div>\n )",
|
|
1374
|
+
"import { toast } from '@imj_media';\n\n toast.success('Toast con API legacy');\n toast.error('Error con toast legacy');\n toast.info('Info con toast legacy');",
|
|
1375
|
+
"// ============================================\n // FORMA ANTIGUA (toast)\n // ============================================\n import { toast, Toaster } from '@imj_media';\n \n toast.success(\"Mensaje\")\n toast.error(\"Error\")\n toast.info(\"Info\")\n toast.warning(\"Warning\")\n\n // ============================================\n // FORMA NUEVA (notify) - Recomendada\n // ============================================\n import { notify, Messaging } from '@imj_media';\n \n notify.success(\"Mensaje\")\n notify.error(\"Error\")\n notify.info(\"Info\")\n notify.warning(\"Warning\")\n \n // ✨ Métodos adicionales\n notify.message({ stackGroup: 'secondary', title: 'Mensaje neutro' })\n notify.message({ title: 'Mensaje de marca' })",
|
|
1376
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\",
|
|
1377
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n title: 'Cola única',\n message: 'Todas las intenciones comparten el mazo auto.',\n duration: 8000,\n appearance: { intent: 'informativa' },\n });",
|
|
1378
|
+
"import { notify } from '@imj_media';\n\n notify.message({\n stackGroup: 'primary',\n title: 'Brand',\n message: 'Mazo primary',\n duration: 8000,\n });\n\n notify.message({\n stackGroup: 'secondary',\n title: 'Neutral',\n message: 'Mazo secondary',\n duration: 8000,\n });",
|
|
1379
|
+
"import { notification } from '@imj_media';\n\n notification.message({ title: 'Encola en auto' });\n notification.dismissStack('auto');\n notification.dismissStack('primary');\n notification.dismissStack('secondary');",
|
|
1380
|
+
"// 1) App\n import { notify, Messaging } from '@imj_media';\n\n export const App = () => (\n <>\n <Messaging />\n {/* … */}\n </>\n );\n\n // 2) Defaults del servicio (opcional)\n notify.configureNotification({ duration: 8000, stackMax: 3, showTimer: true });\n\n // 3) Encolar: campos de tarjeta en la raíz (equivalente a anidarlos en \\`notification\\`)\n notify.message({\n title: 'Título corto',\n message: 'Cuerpo por defecto',\n duration: 10000,\n stackGroup: 'secondary', // u omitir → mazo \\`auto\\`\n appearance: { intent: 'preventiva', variant: 'outlined' },\n content: { title: 'Título corto', kind: 'default', description: 'Texto largo…' },\n meta: { presentation: 'popup' },\n events: { onClose: () => {} },\n });",
|
|
1381
|
+
"import { notify, Messaging } from '@imj_media';\n\n // En la app: <Messaging />\n notify.message({\n title: 'Aviso',\n message: 'Texto breve con la apariencia por defecto del sistema.',\n duration: 8000,\n // Equivale a appearance: { intent: 'informativa' } (valor por defecto del componente Notification)\n });",
|
|
1382
|
+
"import { notify } from '@imj_media';\n\n // Mismo tipo: stack compartido (máx. stackMax, por defecto 3)\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' })\n notify.message({ stackGroup: 'primary', title: 'Mensaje 3' }) // Contador en la frontal\n\n // Configurar tamaño del stack (opcional)\n notify.configureNotification({ stackMax: 5 })\n\n // stackGroup 'secondary' usa otro mazo\n notify.message({ stackGroup: 'secondary', title: 'Recordatorio' })\n notify.message({ stackGroup: 'secondary', title: 'Otro recordatorio' })",
|
|
1383
|
+
"import { notify } from '@imj_media';\n\n // Mismo mazo primary: cada encolado con título y mensaje distintos\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n subtitle: 'Hora 14:05:12',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // En la app: setInterval o scheduler que encole copy nuevo cada N ms\n // notify.message({ stackGroup: 'primary', title: '…', message: '…' });",
|
|
1384
|
+
"import { notify } from '@imj_media';\n\n // Una notificación en el mazo (sin pie de apilado)\n notify.message({\n stackGroup: 'primary',\n title: 'Actualización · #1',\n message: 'Revisa el panel principal. (seq 1)',\n });\n\n // Dos en el mismo mazo: la frontal muestra leyenda personalizada\n notify.message({\n stackGroup: 'primary',\n title: 'Aviso · #2',\n message: 'Hay cambios pendientes. (seq 2)',\n });\n notify.message({\n stackGroup: 'primary',\n title: 'Alerta · #3',\n message: 'La cola se ha actualizado. (seq 3)',\n stackSummaryLegend: 'Tienes 8 mensajes sin leer',\n });",
|
|
1385
|
+
"// Cada nueva notificación reinicia el timer\n notify.message({ stackGroup: 'primary', title: 'Mensaje 1' }) // Timer: 5s\n // Después de 2s...\n notify.message({ stackGroup: 'primary', title: 'Mensaje 2' }) // Timer: 5s (reiniciado)"
|
|
1386
|
+
]
|
|
1387
|
+
}
|
|
1388
|
+
]
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
"id": "Modal",
|
|
1392
|
+
"path": "src/modules/Modal",
|
|
1393
|
+
"legacy": false,
|
|
1394
|
+
"compositionType": 2,
|
|
1395
|
+
"exports": [
|
|
1396
|
+
{
|
|
1397
|
+
"name": "Modal",
|
|
1398
|
+
"kind": "compound-root",
|
|
1399
|
+
"description": {
|
|
1400
|
+
"primary": "storybook",
|
|
1401
|
+
"storybook": "El componente ModalImage permite mostrar una imagen dentro de un modal. Soporta modo thumbnail que se expande al hacer clic, opcionalmente otra URL (",
|
|
1402
|
+
"readme": "# Modal Component\n\nComponente de modal/diálogo versátil y configurable con soporte para múltiples tamaños, botones personalizados, tabs, iconos, badges y un sistema de compound components.\n\n## Estructura\n\n```\nModal/\n├── Modal.tsx # Componente principal\n├── components/ # Subcomponentes (Header, Body, Footer)\n├── hooks/ # Hooks personalizados\n├── context/ # Context para estado del modal\n├── stories/\n│ └── Modal.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Modal } from '@imj_media/ui';\n\n// Modal simple\n<Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Título del Modal\"\n>\n <Modal.Body>Contenido del modal</Modal.Body>\n</Modal>\n\n// Modal con footer\n<Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Confirmar acción\"\n>\n <Modal.Body>¿Estás seguro de que deseas continuar?</Modal.Body>\n <Modal.Footer>\n <Button onClick={() => setIsOpen(false)}>Cancelar</Button>\n <Button onClick={handleConfirm}>Confirmar</Button>\n </Modal.Footer>\n</Modal>\n```\n\n## Props Principales\n\n### Control del Modal\n\n- `isOpen: boolean` - Si el modal está abierto\n- `onClose: () => void` - Callback para cerrar el modal\n- `title?: string` - Título del modal\n- `size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'` - Tamaño del modal (default: `'md'`)\n- `zIndex?: number` - Z-index del modal (default: `52`, por encima de capas sticky de la tabla)\n\n### Comportamiento\n\n- `showCloseButton?: boolean` - Mostrar botón de cerrar (default: `true`)\n- `disableEscapeClose?: boolean` - Deshabilitar cierre con Escape (default: `false`)\n- `disableOutsideClick?: boolean` - Deshabilitar cierre al hacer clic fuera (default: `false`)\n- `disableOutsideTab?: boolean` - Deshabilitar navegación fuera del modal (default: `true`)\n\n### Iconos y Badges\n\n- `icon?: IconType | AnyIconDefinition` - Icono principal del modal\n- `iconConfig?: ButtonIconConfig` - Configuración com",
|
|
1403
|
+
"confidence": "high"
|
|
1404
|
+
},
|
|
1405
|
+
"examples": [
|
|
1406
|
+
"import { useState } from 'react';\n import { Modal } from '@/modules/Modal';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n const handleClose = () => {\n setIsOpen(false);\n };\n\n return (\n <div>\n <Button onClick={() => setIsOpen(true)}>\n Abrir Modal\n </Button>\n <Modal\n isOpen={isOpen}\n onClose={handleClose}\n title=\"Modal Básico\"\n >\n <Modal.Body>\n <p>Este es un modal básico con configuración por defecto.</p>\n <p>Incluye título, botón de cerrar y footer automático.</p>\n </Modal.Body>\n </Modal>\n </div>\n )\n }",
|
|
1407
|
+
"<Modal\n isOpen={isOpen}\n onClose={handleClose}\n title=\"Título\"\n closeButton={{ tooltip: true }}\n>\n <Modal.Body>…</Modal.Body>\n</Modal>\n\n<Modal\n …\n closeButton={{ tooltip: true, tooltipLabel: 'Close' }}\n/>",
|
|
1408
|
+
"import { useState } from 'react';\n import { Modal } from '@/modules/Modal';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n const handleClose = () => {\n setIsOpen(false);\n };\n\n return (\n <div>\n <Button onClick={() => setIsOpen(true)}>\n Abrir Modal\n </Button>\n <Modal\n isOpen={isOpen}\n onClose={handleClose}\n title=\"Modal\"\n cancelButtonSlotLeft={faMinusCircle}\n successButtonSlotRight={faPlusCircle}\n >\n <Modal.Body>\n <p>Este es un modal con iconos en los botones.</p>\n </Modal.Body>\n </Modal>\n </div>\n )\n }",
|
|
1409
|
+
"<Modal\n isOpen={isOpen}\n onClose={handleClose}\n title=\"Confirmar cambios\"\n footerSlotLayout=\"spread\"\n cancelButtonSlotLeft={faTimes}\n successButtonSlotRight={faCheck}\n onCancel={handleClose}\n onSuccess={handleSave}\n closeAtSuccess\n>\n <Modal.Body>…</Modal.Body>\n</Modal>",
|
|
1410
|
+
"import { useState } from 'react';\n import { Modal } from '@/modules/Modal';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n const handleClose = () => {\n setIsOpen(false);\n };\n\n return (\n <div>\n <Button onClick={() => setIsOpen(true)}>\n Abrir Modal\n </Button>\n <Modal\n isOpen={isOpen}\n onClose={handleClose}\n title=\"Modal Básico\"\n headerButtonIcon={faStar}\n headerButtonOnClick={() => {\n console.log('clicked');\n }}\n >\n <Modal.Body>\n <p>Este es un modal básico con configuración por defecto.</p>\n <p>Incluye título, botón de cerrar y footer automático.</p>\n </Modal.Body>\n </Modal>\n </div>\n )\n }",
|
|
1411
|
+
"import { useState } from 'react';\nimport { Modal } from '@/modules/Modal';\n\nexport default function DifferentThumbnailSizes() {\n const [isOpen, setIsOpen] = useState(false);\n const [thumbnailSize, setThumbnailSize] = useState<'sm' | 'md' | 'lg' | 'xl' | 'auto'>('md');\n\n return (\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title=\"Imagen\" size=\"lg\">\n <Modal.Body>\n <div className=\"flex flex-col gap-4\">\n <p>Lorem ipsum dolor sit amet...</p>\n <div className=\"flex justify-center\">\n <Modal.Image\n src={imageSrc}\n alt={imageAlt}\n thumbnailMode={true}\n thumbnailSize={thumbnailSize}\n />\n </div>\n <p>Duis aute irure dolor...</p>\n </div>\n </Modal.Body>\n </Modal>\n );\n}",
|
|
1412
|
+
"import { useState } from 'react';\nimport { Modal } from '@/modules/Modal';\n\nexport default function DifferentPadding() {\n const [isOpen, setIsOpen] = useState(false);\n const [padding, setPadding] = useState<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>('md');\n\n return (\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title=\"Imagen\" size=\"lg\">\n <Modal.Body>\n <Modal.Image\n src={imageSrc}\n alt={imageAlt}\n thumbnailMode={true}\n thumbnailSize=\"md\"\n padding={padding}\n />\n </Modal.Body>\n </Modal>\n );\n}",
|
|
1413
|
+
"import { useState } from 'react';\nimport { Modal } from '@/modules/Modal';\n\nexport default function DifferentObjectFit() {\n const [isOpen, setIsOpen] = useState(false);\n const [objectFit, setObjectFit] = useState<'cover' | 'contain' | 'fill' | 'none' | 'scale-down'>('cover');\n\n return (\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title=\"Imagen\" size=\"lg\">\n <Modal.Body>\n <Modal.Image\n src={imageSrc}\n alt={imageAlt}\n thumbnailMode={true}\n thumbnailSize=\"md\"\n objectFit={objectFit}\n />\n </Modal.Body>\n </Modal>\n );\n}",
|
|
1414
|
+
"import { useState } from 'react';\nimport { Modal } from '@/modules/Modal';\n\nexport default function CombinedProps() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title=\"Imagen Completa\" size=\"xl\">\n <Modal.Body>\n <Modal.Image\n src={imageSrc}\n alt={imageAlt}\n thumbnailMode={true}\n thumbnailSize=\"lg\"\n padding=\"lg\"\n objectFit=\"cover\"\n expandButtonIcon={faImage}\n />\n </Modal.Body>\n </Modal>\n );\n}",
|
|
1415
|
+
"import { useState } from 'react';\nimport { Modal } from '@/modules/Modal';\n\nexport default function DifferentModalSizes() {\n const [isOpen, setIsOpen] = useState(false);\n const [modalSize, setModalSize] = useState<'sm' | 'md' | 'lg' | 'xl'>('lg');\n\n return (\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title=\"Modal\" size={modalSize}>\n <Modal.Body>\n <Modal.Image\n src={imageSrc}\n alt={imageAlt}\n thumbnailMode={true}\n thumbnailSize=\"md\"\n />\n </Modal.Body>\n </Modal>\n );\n}",
|
|
1416
|
+
"import { useState, useMemo } from 'react';\nimport { Modal } from '@/modules/Modal';\nimport { Table } from '@/modules/Table';\n\n// Definir columnas y datos...\nconst columnasModal = [/* ... */];\nconst datosEjemplo = [/* ... */];\n\nexport function TablaEnModal() {\n const [isOpen, setIsOpen] = useState(false);\n const rows = useMemo(() => datosEjemplo, []);\n\n return (\n <>\n <button onClick={() => setIsOpen(true)}>Abrir modal con tabla</button>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Listado de usuarios\"\n size=\"xl\"\n >\n <Modal.Body>\n <div className=\"ui-h-[400px] ui-min-h-0\">\n <Table\n columns={columnasModal}\n rows={rows}\n empty={{ title: 'Sin datos', description: 'No hay registros para mostrar.' }}\n />\n </div>\n </Modal.Body>\n </Modal>\n </>\n );\n}",
|
|
1417
|
+
"import { useState, useMemo } from 'react';\nimport { Modal } from '@/modules/Modal';\nimport { Table } from '@/modules/Table';\n\n// Definir columnas y datos...\nconst columnasModal = [/* ... */];\nconst datosEjemplo = [/* ... */];\n\nexport function TablaEnModal() {\n const [isOpen, setIsOpen] = useState(false);\n const rows = useMemo(() => datosEjemplo, []);\n\n return (\n <>\n <button onClick={() => setIsOpen(true)}>Abrir modal con tabla</button>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Listado de usuarios\"\n size=\"xl\"\n >\n <Modal.Body>\n <div className=\"ui-h-[400px] ui-min-h-0\">\n <Table\n columns={columnasModal}\n rows={rows}\n empty={{ title: 'Sin datos', description: 'No hay registros para mostrar.' }}\n />\n </div>\n </Modal.Body>\n </Modal>\n </>\n );\n}"
|
|
1418
|
+
]
|
|
1419
|
+
}
|
|
1420
|
+
],
|
|
1421
|
+
"compositionRecipe": {
|
|
1422
|
+
"pieces": [
|
|
1423
|
+
"Modal",
|
|
1424
|
+
"Modal.Header",
|
|
1425
|
+
"Modal.Body",
|
|
1426
|
+
"Modal.Footer",
|
|
1427
|
+
"Modal.Image"
|
|
1428
|
+
],
|
|
1429
|
+
"steps": [
|
|
1430
|
+
"Controla visibilidad con isOpen y onClose en Modal (raíz).",
|
|
1431
|
+
"Compón Header opcional, Body con el contenido y Footer con acciones.",
|
|
1432
|
+
"Para tabs, usa tabsConfig en la raíz en lugar de props tabs planas deprecadas."
|
|
1433
|
+
],
|
|
1434
|
+
"storyRefs": [
|
|
1435
|
+
"Modal.stories.tsx:Default",
|
|
1436
|
+
"Modal.stories.tsx:WithTabs"
|
|
1437
|
+
],
|
|
1438
|
+
"snippet": "<Modal isOpen={open} onClose={() => setOpen(false)} title=\"Título\">\n <Modal.Body>Contenido</Modal.Body>\n <Modal.Footer>\n <Button onClick={() => setOpen(false)}>Cerrar</Button>\n </Modal.Footer>\n</Modal>"
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
"id": "Notification",
|
|
1443
|
+
"path": "src/modules/Notification",
|
|
1444
|
+
"legacy": false,
|
|
1445
|
+
"compositionType": 1,
|
|
1446
|
+
"exports": [
|
|
1447
|
+
{
|
|
1448
|
+
"name": "Notification",
|
|
1449
|
+
"kind": "component",
|
|
1450
|
+
"description": {
|
|
1451
|
+
"primary": "storybook",
|
|
1452
|
+
"storybook": "Notificación (Figma Notification): compone",
|
|
1453
|
+
"jsdoc": "Notificación de producto según Figma ([Notification](https://www.figma.com/design/aWDHIXKjf82m6udooBUeZG/Notification)): compone {@link Alert}\ncon API agrupada (`content`, `leading`, `appearance`, `meta`, `events`).",
|
|
1454
|
+
"confidence": "high"
|
|
1455
|
+
},
|
|
1456
|
+
"examples": [
|
|
1457
|
+
"import { Notification } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Notification\n open\n content={{\n title: 'Notification Title',\n subtitle: 'Subtitle',\n description:\n 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet.',\n }}\n leading={{ source: 'general' }}\n appearance={{ intent: 'informativa', showCloseButton: true }}\n meta={{\n presentation: 'popup',\n stackSummary: '5 notificaciones más',\n }}\n events={{}}\n />\n );\n}",
|
|
1458
|
+
"import { Notification } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <div className=\"ui-w-[260px] ui-max-w-full\">\n <Notification\n open\n content={{\n title:\n 'Título de notificación deliberadamente largo que debe truncarse con puntos suspensivos',\n subtitle:\n 'Subtítulo extenso en una sola línea cuando el espacio horizontal es limitado en el panel',\n description:\n 'Cuerpo del mensaje también largo: una sola línea con ellipsis para mantener la altura de la tarjeta predecible.',\n }}\n leading={{ source: 'general' }}\n appearance={{ intent: 'informativa', showCloseButton: true }}\n meta={{ presentation: 'popup' }}\n events={{}}\n />\n </div>\n );\n}",
|
|
1459
|
+
"import { Notification } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <div className=\"ui-w-[260px] ui-max-w-full\">\n <Notification\n open\n content={{\n kind: 'message',\n title: 'Título largo que se corta en una sola línea con ellipsis en panel estrecho',\n subtitle:\n 'Subtítulo igualmente extenso para validar truncado junto al icono y al cerrar',\n messageText:\n 'Alex Manrique: mensaje citado muy largo que debe mostrarse en una sola línea dentro del panel con fondo y puntos suspensivos al final.',\n }}\n leading={{ source: 'general' }}\n appearance={{ intent: 'informativa', showCloseButton: true }}\n meta={{ presentation: 'popup' }}\n events={{}}\n />\n </div>\n );\n}",
|
|
1460
|
+
"import { Notification } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Notification\n open\n content={{\n title: 'Notification Title',\n subtitle: 'Subtitle',\n description:\n 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet.',\n }}\n leading={{ source: 'general' }}\n appearance={{ intent: 'confirmacion', showCloseButton: true }}\n meta={{ presentation: 'popup', stackSummary: '5 notificaciones más' }}\n events={{}}\n />\n );\n}",
|
|
1461
|
+
"import { Notification } from '@imj_media/ui';\n\nexport default function Example() {\n return (\n <Notification\n open\n content={{\n title: 'Notification Title',\n subtitle: 'Subtitle',\n description:\n 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet.',\n }}\n leading={{ source: 'general' }}\n appearance={{ intent: 'preventiva', showCloseButton: true }}\n meta={{ presentation: 'popup', stackSummary: '5 notificaciones más' }}\n events={{}}\n />\n );\n}"
|
|
1462
|
+
]
|
|
1463
|
+
}
|
|
1464
|
+
]
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
"id": "Pagination",
|
|
1468
|
+
"path": "src/modules/Pagination",
|
|
1469
|
+
"legacy": false,
|
|
1470
|
+
"compositionType": 1,
|
|
1471
|
+
"exports": [
|
|
1472
|
+
{
|
|
1473
|
+
"name": "Pagination",
|
|
1474
|
+
"kind": "component",
|
|
1475
|
+
"description": {
|
|
1476
|
+
"primary": "storybook",
|
|
1477
|
+
"storybook": "El componente Pagination permite navegar entre páginas de contenido.",
|
|
1478
|
+
"jsdoc": "Pagination - Componente de paginación\nComponente de paginación que permite navegar entre páginas de datos.\nSoporta selector de tamaño de página, contador de páginas visibles y navegación con botones.",
|
|
1479
|
+
"confidence": "high"
|
|
1480
|
+
},
|
|
1481
|
+
"examples": [
|
|
1482
|
+
"import { Pagination } from '@/modules/Pagination';\n import { useState } from 'react';\n\n export default function Example() {\n const [currentPage, setCurrentPage] = useState(1);\n\n return (\n <Pagination \n currentPage={currentPage} \n pageCount={10} \n onPageChange={setCurrentPage} \n />\n )\n }",
|
|
1483
|
+
"import { Pagination } from '@/modules/Pagination';\n import { useState } from 'react';\n\n export default function Example() {\n const [currentPage, setCurrentPage] = useState(1);\n\n return (\n <Pagination \n currentPage={currentPage} \n pageCount={10} \n onPageChange={setCurrentPage} \n />\n )\n }",
|
|
1484
|
+
"import { Pagination } from '@/modules/Pagination';\n import { useState } from 'react';\n\n export default function Example() {\n const [currentPage, setCurrentPage] = useState(1);\n\n return (\n <Pagination \n currentPage={currentPage} \n pageCount={10} \n onPageChange={setCurrentPage} \n />\n )\n }",
|
|
1485
|
+
"import { Pagination } from '@/modules/Pagination';\n import { useState } from 'react';\n\n export default function Example() {\n const [currentPage, setCurrentPage] = useState(1);\n\n return (\n <Pagination \n currentPage={currentPage} \n pageCount={10} \n onPageChange={setCurrentPage} \n />\n )\n }",
|
|
1486
|
+
"import { Pagination } from '@/modules/Pagination';\n import { useState } from 'react';\n\n export default function Example() {\n const [currentPage, setCurrentPage] = useState(1);\n\n return (\n <Pagination \n currentPage={currentPage} \n pageCount={10} \n onPageChange={setCurrentPage} \n />\n )\n }"
|
|
1487
|
+
]
|
|
1488
|
+
}
|
|
1489
|
+
]
|
|
1490
|
+
},
|
|
1491
|
+
{
|
|
1492
|
+
"id": "PickerColor",
|
|
1493
|
+
"path": "src/modules/PickerColor",
|
|
1494
|
+
"legacy": false,
|
|
1495
|
+
"compositionType": 1,
|
|
1496
|
+
"exports": [
|
|
1497
|
+
{
|
|
1498
|
+
"name": "PickerColor",
|
|
1499
|
+
"kind": "component",
|
|
1500
|
+
"description": {
|
|
1501
|
+
"primary": "storybook",
|
|
1502
|
+
"storybook": "Un componente para seleccionar colores en formato hexadecimal. Incluye un selector visual con colores recientes y recomendados, y persistencia en localStorage.",
|
|
1503
|
+
"confidence": "medium"
|
|
1504
|
+
},
|
|
1505
|
+
"examples": []
|
|
1506
|
+
}
|
|
1507
|
+
]
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
"id": "Picture",
|
|
1511
|
+
"path": "src/modules/Picture",
|
|
1512
|
+
"legacy": false,
|
|
1513
|
+
"compositionType": 1,
|
|
1514
|
+
"exports": [
|
|
1515
|
+
{
|
|
1516
|
+
"name": "Picture",
|
|
1517
|
+
"kind": "component",
|
|
1518
|
+
"description": {
|
|
1519
|
+
"primary": "storybook",
|
|
1520
|
+
"storybook": "El componente Picture permite mostrar imágenes con diferentes formatos y tamaños.",
|
|
1521
|
+
"jsdoc": "Inactivo alineado a Figma **Cards** [233:11229](https://www.figma.com/design/3w0SWvV7C5tDKUybsOcgA4/Cards?node-id=233-11229):\ncapa `bg-fill-tertiary` (#f0f1f2) como en Figma; contenedor con `mix-blend-luminosity`; imagen con brillo/contraste suaves.\nSi un consumidor fuerza `img { filter: none !important }` o anula `mix-blend-mode`, el resultado puede no coincidir.\nSin `src` válido o tras error de carga de imagen se muestra el icono Font Awesome **Image** (regular) en superficie terciaria, en lugar de un SVG raster externo.\n/\nconst PICTURE_DISABLED_IMG_STYLE: CSSProperties = {\n WebkitFilter: 'brightness(1.06) contrast(0.88)',\n filter: 'brightness(1.06) contrast(0.88)',\n};\n\n/**\nImagen con variantes de tamaño, radio y estado *disabled* alineado a Figma.\nLos `<img>` usan **`draggable={false}",
|
|
1522
|
+
"confidence": "high"
|
|
1523
|
+
},
|
|
1524
|
+
"examples": [
|
|
1525
|
+
"import { Picture } from '@imj_media/ui';\n\n export default function Example() {\n const IMAGE = 'https://devobp.imjmedia.com.mx/uploads/small_IMJ-MTY-PAN-O-6458A.jpg'\n return <Picture src={IMAGE} alt=\"Imagen de ejemplo\" />\n }",
|
|
1526
|
+
"import { Picture } from '@/modules/Picture';\n\n export default function Example() {\n const IMAGE = 'https://devobp.imjmedia.com.mx/uploads/small_IMJ-MTY-PAN-O-6458A.jpg'\n return <StoryBox.Content>\n <Picture size=\"xs\" src={IMAGE} alt=\"Imagen de ejemplo\" />\n <Picture size=\"sm\" src={IMAGE} alt=\"Imagen de ejemplo\" />\n <Picture size=\"md\" src={IMAGE} alt=\"Imagen de ejemplo\" />\n <Picture size=\"lg\" src={IMAGE} alt=\"Imagen de ejemplo\" />\n <Picture size=\"xl\" src={IMAGE} alt=\"Imagen de ejemplo\" />\n </StoryBox.Content>\n }",
|
|
1527
|
+
"import { Picture } from '@/modules/Picture';\n\n export default function Example() {\n const IMAGE = 'https://devobp.imjmedia.com.mx/uploads/small_IMJ-MTY-PAN-O-6458A.jpg'\n return <StoryBox.Content>\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"none\" />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"sm\" />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"md\" />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"pill\" />\n </StoryBox.Content>\n }",
|
|
1528
|
+
"import { Picture } from '@/modules/Picture';\n\n export default function Example() {\n const IMAGE = 'https://devobp.imjmedia.com.mx/uploads/small_IMJ-MTY-PAN-O-6458A.jpg'\n return <StoryBox.Content>\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"none\" square />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"sm\" square />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"md\" square />\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" radius=\"pill\" square />\n </StoryBox.Content>\n }",
|
|
1529
|
+
"import { Picture } from '@/modules/Picture';\n\n export default function Example() {\n const IMAGE = 'https://devobp.imjmedia.com.mx/uploads/small_IMJ-MTY-PAN-O-6458A.jpg'\n return <StoryBox.Content>\n <Picture src={IMAGE} alt=\"Imagen de ejemplo\" shadow />\n </StoryBox.Content>\n }"
|
|
1530
|
+
]
|
|
1531
|
+
}
|
|
1532
|
+
]
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
"id": "Popup",
|
|
1536
|
+
"path": "src/modules/Popup",
|
|
1537
|
+
"legacy": false,
|
|
1538
|
+
"compositionType": 1,
|
|
1539
|
+
"exports": [
|
|
1540
|
+
{
|
|
1541
|
+
"name": "Popup",
|
|
1542
|
+
"kind": "component",
|
|
1543
|
+
"description": {
|
|
1544
|
+
"primary": "jsdoc",
|
|
1545
|
+
"jsdoc": "Popup - Componente de popup/dropdown posicionable y configurable\nComponente de popup que se posiciona relativamente a un trigger, con soporte para múltiples\nposiciones, cierre automático, tooltips, iconos y slots personalizados.",
|
|
1546
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1547
|
+
"confidence": "medium"
|
|
1548
|
+
},
|
|
1549
|
+
"examples": [
|
|
1550
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1551
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1552
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1553
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1554
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1555
|
+
]
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
"name": "Popover",
|
|
1559
|
+
"kind": "component",
|
|
1560
|
+
"description": {
|
|
1561
|
+
"primary": "readme",
|
|
1562
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1563
|
+
"confidence": "low"
|
|
1564
|
+
},
|
|
1565
|
+
"examples": [
|
|
1566
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1567
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1568
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1569
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1570
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1571
|
+
]
|
|
1572
|
+
},
|
|
1573
|
+
{
|
|
1574
|
+
"name": "POPUP_OPEN_ON_HOVER_CLOSE_DELAY_MS",
|
|
1575
|
+
"kind": "component",
|
|
1576
|
+
"description": {
|
|
1577
|
+
"primary": "jsdoc",
|
|
1578
|
+
"jsdoc": "Retardo por defecto al abrir con `openOnHover={true}` (ms). */\nexport const POPUP_OPEN_ON_HOVER_DEFAULT_MS = 200;\n/** Margen al salir del trigger o del panel antes de cerrar (ms).",
|
|
1579
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1580
|
+
"confidence": "medium"
|
|
1581
|
+
},
|
|
1582
|
+
"examples": [
|
|
1583
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1584
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1585
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1586
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1587
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1588
|
+
]
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
"name": "POPUP_OPEN_ON_HOVER_DEFAULT_MS",
|
|
1592
|
+
"kind": "component",
|
|
1593
|
+
"description": {
|
|
1594
|
+
"primary": "jsdoc",
|
|
1595
|
+
"jsdoc": "Retardo por defecto al abrir con `openOnHover={true}` (ms).",
|
|
1596
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1597
|
+
"confidence": "medium"
|
|
1598
|
+
},
|
|
1599
|
+
"examples": [
|
|
1600
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1601
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1602
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1603
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1604
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1605
|
+
]
|
|
1606
|
+
},
|
|
1607
|
+
{
|
|
1608
|
+
"name": "POPUP_ARROW_TILT_LEFT_DEG",
|
|
1609
|
+
"kind": "component",
|
|
1610
|
+
"description": {
|
|
1611
|
+
"primary": "jsdoc",
|
|
1612
|
+
"jsdoc": "Sin contorno en el trazo + sombra (mismo criterio que el panel con `showPanelBorder={false}`).\nEl relleno sigue usando el token de fondo del panel.\n/\n elevated?: boolean;\n}\n\n/**\nAncho horizontal del beak respecto al path base (`1` = ancho de diseño; menor = más estrecho).\nSe aplica con `scale` en torno a x=14 (centro del viewBox).\n/\nexport const POPUP_ARROW_WIDTH_SCALE = 0.7;\n\n/**\nInclinación fina del beak solo en bordes laterales (deg); 0 = perpendicular a `-90°` / `90°`.\nValores separados por si en diseño hace falta asimetría.",
|
|
1613
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1614
|
+
"confidence": "medium"
|
|
1615
|
+
},
|
|
1616
|
+
"examples": [
|
|
1617
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1618
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1619
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1620
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1621
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1622
|
+
]
|
|
1623
|
+
},
|
|
1624
|
+
{
|
|
1625
|
+
"name": "POPUP_ARROW_TILT_RIGHT_DEG",
|
|
1626
|
+
"kind": "component",
|
|
1627
|
+
"description": {
|
|
1628
|
+
"primary": "readme",
|
|
1629
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1630
|
+
"confidence": "low"
|
|
1631
|
+
},
|
|
1632
|
+
"examples": [
|
|
1633
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1634
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1635
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1636
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1637
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1638
|
+
]
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
"name": "POPUP_ARROW_WIDTH_SCALE",
|
|
1642
|
+
"kind": "component",
|
|
1643
|
+
"description": {
|
|
1644
|
+
"primary": "jsdoc",
|
|
1645
|
+
"jsdoc": "Sin contorno en el trazo + sombra (mismo criterio que el panel con `showPanelBorder={false}`).\nEl relleno sigue usando el token de fondo del panel.\n/\n elevated?: boolean;\n}\n\n/**\nAncho horizontal del beak respecto al path base (`1` = ancho de diseño; menor = más estrecho).\nSe aplica con `scale` en torno a x=14 (centro del viewBox).",
|
|
1646
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1647
|
+
"confidence": "medium"
|
|
1648
|
+
},
|
|
1649
|
+
"examples": [
|
|
1650
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1651
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1652
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1653
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1654
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1655
|
+
]
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
"name": "POPUP_PANEL_Z_INDEX_BASE",
|
|
1659
|
+
"kind": "component",
|
|
1660
|
+
"description": {
|
|
1661
|
+
"primary": "jsdoc",
|
|
1662
|
+
"jsdoc": "Acota el puntero al rectángulo del trigger en coordenadas de viewport.\nDevuelve la esquina superior izquierda de un ancla 1×1 lógica dentro del trigger\n(recorrido píxel a píxel cuando el trigger tiene tamaño entero en CSS px).\n/\nexport function clampClientPointForPopupAnchor(\n triggerRect: DOMRectReadOnly,\n clientX: number,\n clientY: number,\n): { x: number; y: number } {\n const rw = Math.max(triggerRect.width, 0);\n const rh = Math.max(triggerRect.height, 0);\n const insetX = rw > 0 ? Math.min(1, rw) : 0;\n const insetY = rh > 0 ? Math.min(1, rh) : 0;\n const maxX = rw > 0 ? triggerRect.right - insetX : triggerRect.left;\n const maxY = rh > 0 ? triggerRect.bottom - insetY : triggerRect.top;\n const x = Math.min(Math.max(clientX, triggerRect.left), maxX);\n const y = Math.min(Math.max(c",
|
|
1663
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1664
|
+
"confidence": "medium"
|
|
1665
|
+
},
|
|
1666
|
+
"examples": [
|
|
1667
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1668
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1669
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1670
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1671
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1672
|
+
]
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
"name": "Z_INDEX_MODAL_ABOVE_POPUP",
|
|
1676
|
+
"kind": "component",
|
|
1677
|
+
"description": {
|
|
1678
|
+
"primary": "jsdoc",
|
|
1679
|
+
"jsdoc": "Acota el puntero al rectángulo del trigger en coordenadas de viewport.\nDevuelve la esquina superior izquierda de un ancla 1×1 lógica dentro del trigger\n(recorrido píxel a píxel cuando el trigger tiene tamaño entero en CSS px).\n/\nexport function clampClientPointForPopupAnchor(\n triggerRect: DOMRectReadOnly,\n clientX: number,\n clientY: number,\n): { x: number; y: number } {\n const rw = Math.max(triggerRect.width, 0);\n const rh = Math.max(triggerRect.height, 0);\n const insetX = rw > 0 ? Math.min(1, rw) : 0;\n const insetY = rh > 0 ? Math.min(1, rh) : 0;\n const maxX = rw > 0 ? triggerRect.right - insetX : triggerRect.left;\n const maxY = rh > 0 ? triggerRect.bottom - insetY : triggerRect.top;\n const x = Math.min(Math.max(clientX, triggerRect.left), maxX);\n const y = Math.min(Math.max(c",
|
|
1680
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1681
|
+
"confidence": "medium"
|
|
1682
|
+
},
|
|
1683
|
+
"examples": [
|
|
1684
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1685
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1686
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1687
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1688
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1689
|
+
]
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
"name": "Z_INDEX_TOOLTIP",
|
|
1693
|
+
"kind": "component",
|
|
1694
|
+
"description": {
|
|
1695
|
+
"primary": "jsdoc",
|
|
1696
|
+
"jsdoc": "Acota el puntero al rectángulo del trigger en coordenadas de viewport.\nDevuelve la esquina superior izquierda de un ancla 1×1 lógica dentro del trigger\n(recorrido píxel a píxel cuando el trigger tiene tamaño entero en CSS px).\n/\nexport function clampClientPointForPopupAnchor(\n triggerRect: DOMRectReadOnly,\n clientX: number,\n clientY: number,\n): { x: number; y: number } {\n const rw = Math.max(triggerRect.width, 0);\n const rh = Math.max(triggerRect.height, 0);\n const insetX = rw > 0 ? Math.min(1, rw) : 0;\n const insetY = rh > 0 ? Math.min(1, rh) : 0;\n const maxX = rw > 0 ? triggerRect.right - insetX : triggerRect.left;\n const maxY = rh > 0 ? triggerRect.bottom - insetY : triggerRect.top;\n const x = Math.min(Math.max(clientX, triggerRect.left), maxX);\n const y = Math.min(Math.max(c",
|
|
1697
|
+
"readme": "# Popup Component\n\nComponente de popup/dropdown posicionable y configurable que se posiciona relativamente a un trigger, con soporte para múltiples posiciones, cierre automático, tooltips e iconos.\n\n## Estructura\n\n```\nPopup/\n├── components/\n│ └── organisms/\n│ └── Popup.tsx # Componente principal\n├── hooks/ # Hooks personalizados\n├── stories/\n│ └── Popup.stories.tsx # Storybook stories\n└── index.ts # Export del módulo\n```\n\n## Uso Básico\n\n```tsx\nimport { Popup } from '@imj_media/ui';\nimport { useRef } from 'react';\n\n// Popup simple\nconst popupRef = useRef<PopupRef>(null);\n\n<Popup ref={popupRef} label=\"Abrir popup\" position=\"bottom-right\">\n <div>Contenido del popup</div>\n</Popup>;\n```\n\n## Props Principales\n\n### Control del Popup\n\n- `label?: string` - Texto del botón trigger\n- `position?: PopupPosition` - Posición del popup relativa al trigger (default: `'bottom-right'`)\n- `offset?: number` - Distancia en píxeles entre el trigger y el popup (default: `6`)\n- `popupId?: string` - ID único del popup (auto-generado si no se proporciona)\n\n### Comportamiento\n\n- `closeOnClickOutside?: boolean` - Cerrar al hacer clic fuera (default: `true`)\n- `closeOnEscape?: boolean` - Cerrar con tecla Escape (default: `true`)\n- `closeOnClick?: boolean` - Cerrar al hacer clic en el trigger (default: `true`)\n- `disabled?: boolean` - Deshabilitar el popup (default: `false`)\n\n### Estilo del Trigger\n\n- `theme?: 'solid' | 'outlined' | 'text' | 'ghost'` - Tema del botón trigger (default: `'solid'`)\n- `color?: ButtonColors` - Color del botón trigger (default: `'tertiary'`)\n- `size?: 'xs' | 'sm' | 'md' | 'lg'` - Tamaño del botón trigger (default: `'xs'`)\n- `rounded?: boolean` - Bordes redondeados (default: `false`)\n- `pill?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'` - Radio de borde (default: `'xs'`)\n- `borderRadius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'` - Radio de borde del popup (default: `'sm'`)\n\n### Slots e Iconos\n\n- `icon?: I",
|
|
1698
|
+
"confidence": "medium"
|
|
1699
|
+
},
|
|
1700
|
+
"examples": [
|
|
1701
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>",
|
|
1702
|
+
"import { BUTTON_SLOT_SPREAD_CENTER } from '@imj_media/ui'; // o tu path de tipos/botón\n\n <Popup\n label=\"Centro\"\n fullWidth\n slotLayout={BUTTON_SLOT_SPREAD_CENTER}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>\n\n <Popup\n label=\"Izquierda\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />\n\n <Popup\n label=\"Derecha\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n rightSlot={faAngleDown}\n />",
|
|
1703
|
+
"<Popup\n label=\"Menú · icono izq.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'right' }}\n leftSlot={faBell}\n >\n {children}\n </Popup>",
|
|
1704
|
+
"<Popup\n label=\"Acción · icono dcha.\"\n fullWidth\n slotLayout={{ var: 'spread', textAlign: 'left' }}\n rightSlot={faAngleDown}\n >\n {children}\n </Popup>",
|
|
1705
|
+
"<Popup\n label=\"Solo texto · inline\"\n fullWidth\n position=\"bottom-center\"\n /* sin leftSlot / rightSlot — slotLayout inline por defecto */\n >\n {children}\n </Popup>"
|
|
1706
|
+
]
|
|
1707
|
+
}
|
|
1708
|
+
]
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
"id": "ProgressBar",
|
|
1712
|
+
"path": "src/modules/ProgressBar",
|
|
1713
|
+
"legacy": false,
|
|
1714
|
+
"compositionType": 1,
|
|
1715
|
+
"exports": [
|
|
1716
|
+
{
|
|
1717
|
+
"name": "ProgressBar",
|
|
1718
|
+
"kind": "component",
|
|
1719
|
+
"description": {
|
|
1720
|
+
"primary": "jsdoc",
|
|
1721
|
+
"jsdoc": "Tamaños válidos para ProgressBar */\nconst VALID_SIZES: ProgressBarSize[] = ['xxs', 'xs', 'sm', 'md', 'lg'];\n\n/**\nHook interno para manejar la cuenta regresiva del ProgressBar.\nAnima el progreso desde un valor inicial hasta 0 en un tiempo determinado.\n/\nconst useCountdown = (\n initialProgress: number,\n countdownSeconds: number | undefined,\n onComplete?: () => void,\n) => {\n const [currentProgress, setCurrentProgress] = useState(initialProgress);\n const intervalRef = useRef<NodeJS.Timeout | null>(null);\n const startTimeRef = useRef<number>(0);\n const hasCompletedRef = useRef(false);\n // Guardar el callback en una ref para evitar que esté en las dependencias del useEffect\n const onCompleteRef = useRef(onComplete);\n\n const INTERVAL_MS = 16; // ~60fps\n\n // Mantener la ref actualizada",
|
|
1722
|
+
"confidence": "medium"
|
|
1723
|
+
},
|
|
1724
|
+
"examples": [
|
|
1725
|
+
"// Modo normal\n<ProgressBar \n progress={75} \n label=\"archivo.zip\"\n eta=\"1m restante\"\n helperText=\"200MB de 512MB\"\n/>\n\n// Modo compacto - barra en línea con el label\n<ProgressBar \n progress={75} \n label=\"archivo.zip\"\n eta=\"1m restante\"\n helperText=\"200MB de 512MB\"\n compact\n/>",
|
|
1726
|
+
"<ProgressBar\n progress={75}\n label=\"archivo.zip\"\n eta=\"1m restante\"\n size=\"sm\"\n color=\"brand\"\n helperText=\"200MB de 512MB\"\n helperTextType=\"size\"\n showCloseButton\n onClose={() => {}}\n withBackground\n/>",
|
|
1727
|
+
"// Uso simple - la barra anima automáticamente de 75% a 0% en 5 segundos\n<ProgressBar \n progress={75}\n countdown={5}\n label=\"Descargando...\"\n onCountdownComplete={() => console.log('¡Completado!')}\n/>\n\n// Con diferentes colores y duraciones\n<ProgressBar \n progress={100}\n countdown={10}\n color=\"warning\"\n label=\"Tiempo restante\"\n onCountdownComplete={() => alert('¡Se acabó el tiempo!')}\n/>",
|
|
1728
|
+
"// Modo normal\n<ProgressBar \n progress={75} \n label=\"archivo.zip\"\n eta=\"1m restante\"\n helperText=\"200MB de 512MB\"\n/>\n\n// Modo compacto - barra en línea con el label\n<ProgressBar \n progress={75} \n label=\"archivo.zip\"\n eta=\"1m restante\"\n helperText=\"200MB de 512MB\"\n compact\n/>",
|
|
1729
|
+
"<ProgressBar\n progress={75}\n label=\"archivo.zip\"\n eta=\"1m restante\"\n size=\"sm\"\n color=\"brand\"\n helperText=\"200MB de 512MB\"\n helperTextType=\"size\"\n showCloseButton\n onClose={() => {}}\n withBackground\n/>"
|
|
1730
|
+
]
|
|
1731
|
+
}
|
|
1732
|
+
]
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
"id": "RadioButton",
|
|
1736
|
+
"path": "src/modules/RadioButton",
|
|
1737
|
+
"legacy": false,
|
|
1738
|
+
"compositionType": 1,
|
|
1739
|
+
"exports": [
|
|
1740
|
+
{
|
|
1741
|
+
"name": "RadioButton",
|
|
1742
|
+
"kind": "component",
|
|
1743
|
+
"description": {
|
|
1744
|
+
"primary": "storybook",
|
|
1745
|
+
"storybook": "Un componente RadioButton personalizado y simple para selecciones únicas. Soporta estados controlado y no controlado.",
|
|
1746
|
+
"jsdoc": "Componente RadioButton - Átomo\nUn radio button personalizable con múltiples estados y variantes de color.\nImplementa tokens semánticos de Figma para consistencia visual.",
|
|
1747
|
+
"confidence": "high"
|
|
1748
|
+
},
|
|
1749
|
+
"examples": [
|
|
1750
|
+
"import { RadioButton } from '@/modules/RadioButton';\n import { useState } from 'react';\n\n export default function Example() {\n const [isChecked, setIsChecked] = useState(false);\n\n return (\n <RadioButton\n label=\"Opción básica\"\n name=\"basic-radio\"\n checked={isChecked}\n onChange={() => setIsChecked(!isChecked)}\n color=\"blue\"\n size=\"md\"\n />\n )\n }",
|
|
1751
|
+
"const [selectedSize, setSelectedSize] = useState('md');\n\n <RadioButton\n label=\"Opción pequeña\"\n name=\"size-radio\"\n checked={selectedSize === 'sm'}\n onChange={() => setSelectedSize('sm')}\n size=\"sm\"\n color=\"blue\"\n />\n <RadioButton\n label=\"Opción mediana\"\n name=\"size-radio\"\n checked={selectedSize === 'md'}\n onChange={() => setSelectedSize('md')}\n size=\"md\"\n color=\"blue\"\n />\n <RadioButton\n label=\"Opción grande\"\n name=\"size-radio\"\n checked={selectedSize === 'lg'}\n onChange={() => setSelectedSize('lg')}\n size=\"lg\"\n color=\"blue\"\n />",
|
|
1752
|
+
"const [selectedColor, setSelectedColor] = useState('blue');\n\n <RadioButton\n label=\"Opción azul\"\n name=\"color-radio\"\n checked={selectedColor === 'blue'}\n onChange={() => setSelectedColor('blue')}\n color=\"blue\"\n />\n <RadioButton\n label=\"Opción verde\"\n name=\"color-radio\"\n checked={selectedColor === 'green'}\n onChange={() => setSelectedColor('green')}\n color=\"green\"\n />\n <RadioButton\n label=\"Opción roja\"\n name=\"color-radio\"\n checked={selectedColor === 'red'}\n onChange={() => setSelectedColor('red')}\n color=\"red\"\n />\n <RadioButton\n label=\"Opción amarilla\"\n name=\"color-radio\"\n checked={selectedColor === 'yellow'}\n onChange={() => setSelectedColor('yellow')}\n color=\"yellow\"\n />\n <RadioButton\n label=\"Opción neutral\"\n name=\"color-radio\"\n checked={selectedColor === 'neutral'}\n onChange={() => setSelectedColor('neutral')}\n color=\"neutral\"\n />",
|
|
1753
|
+
"const [isChecked, setIsChecked] = useState(false);\n\n <RadioButton\n label=\"Opción deshabilitada\"\n name=\"disabled-radio\"\n checked={isChecked}\n onChange={() => setIsChecked(!isChecked)}\n disabled={true}\n color=\"blue\"\n />\n <RadioButton\n label=\"Opción habilitada\"\n name=\"enabled-radio\"\n checked={isChecked}\n onChange={() => setIsChecked(!isChecked)}\n disabled={false}\n color=\"blue\"\n />",
|
|
1754
|
+
"const [isChecked, setIsChecked] = useState(false);\n\n <RadioButton\n label=\"Opción controlada\"\n name=\"controlled-radio\"\n checked={isChecked}\n onChange={() => setIsChecked(!isChecked)}\n color=\"blue\"\n size=\"md\"\n />",
|
|
1755
|
+
"import { RadioButtonGroup } from '@/modules/RadioButton';\n import { useState } from 'react';\n\n export default function Example() {\n const [selectedValue, setSelectedValue] = useState('option1');\n\n return (\n <RadioButtonGroup\n options={[\n { value: 'option1', label: 'Opción 1' },\n { value: 'option2', label: 'Opción 2' },\n { value: 'option3', label: 'Opción 3' },\n { value: 'option4', label: 'Opción 4 (Deshabilitada)', disabled: true },\n ]}\n value={selectedValue}\n onChange={setSelectedValue}\n name=\"basic-group\"\n color=\"blue\"\n size=\"md\"\n />\n )\n }",
|
|
1756
|
+
"const [selectedValue, setSelectedValue] = useState('option1');\n\n <RadioButtonGroup\n options={defaultOptions}\n value={selectedValue}\n onChange={setSelectedValue}\n name=\"controlled-group\"\n color=\"blue\"\n />",
|
|
1757
|
+
"const [selectedValue, setSelectedValue] = useState('option1');\n\n <RadioButtonGroup\n options={defaultOptions}\n value={selectedValue}\n onChange={setSelectedValue}\n name=\"uncontrolled-group\"\n color=\"green\"\n />",
|
|
1758
|
+
"const [selectedSize, setSelectedSize] = useState('md');\n\n <RadioButtonGroup\n options={defaultOptions}\n value={selectedSize}\n onChange={setSelectedSize}\n name=\"size-sm\"\n color=\"blue\"\n />\n <RadioButtonGroup\n options={defaultOptions}\n value={selectedSize}\n onChange={setSelectedSize}\n name=\"size-md\"\n color=\"blue\"\n />\n <RadioButtonGroup\n options={defaultOptions}\n value={selectedSize}\n onChange={setSelectedSize}\n name=\"size-lg\"\n color=\"blue\"\n />",
|
|
1759
|
+
"const [selectedColor, setSelectedColor] = useState('blue');\n\n <RadioButtonGroup\n options={colorOptions}\n value={selectedColor}\n onChange={setSelectedColor}\n name=\"color-blue\"\n color=\"blue\"\n />\n <RadioButtonGroup\n options={colorOptions}\n value={selectedColor}\n onChange={setSelectedColor}\n name=\"color-green\"\n color=\"green\"\n />\n <RadioButtonGroup\n options={colorOptions}\n value={selectedColor}\n onChange={setSelectedColor}\n name=\"color-red\"\n color=\"red\"\n />"
|
|
1760
|
+
]
|
|
1761
|
+
}
|
|
1762
|
+
]
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
"id": "RangeBar",
|
|
1766
|
+
"path": "src/modules/RangeBar",
|
|
1767
|
+
"legacy": false,
|
|
1768
|
+
"compositionType": 1,
|
|
1769
|
+
"exports": [
|
|
1770
|
+
{
|
|
1771
|
+
"name": "RANGE_BAR_TRACK_BLEED_X",
|
|
1772
|
+
"kind": "component",
|
|
1773
|
+
"description": {
|
|
1774
|
+
"primary": "storybook",
|
|
1775
|
+
"storybook": "Control de rango con dos extremos. API agrupada:",
|
|
1776
|
+
"jsdoc": "Padding horizontal del carril: deja sitio para el thumb (20px) centrado en 0% y 100%\nsin recortarse. Debe aplicarse igual en `RangeBar` y en filas de `RangeSelector` alineadas a la pista.",
|
|
1777
|
+
"confidence": "high"
|
|
1778
|
+
},
|
|
1779
|
+
"examples": [
|
|
1780
|
+
"<RangeSelector\n labels={{ title: 'Costo' }}\n range={{ min: 0, max: 100000, step: 1000, value }}\n events={{ onChange: setValue }}\n appearance={{ compact: true }}\n/>",
|
|
1781
|
+
"<RangeSelector\n labels={{ title: 'Costo' }}\n range={{ min: 0, max: 100000, step: 1000, value }}\n events={{ onChange: setValue }}\n appearance={{ compact: true }}\n/>"
|
|
1782
|
+
]
|
|
1783
|
+
}
|
|
1784
|
+
]
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
"id": "Rating",
|
|
1788
|
+
"path": "src/modules/Rating",
|
|
1789
|
+
"legacy": false,
|
|
1790
|
+
"compositionType": 1,
|
|
1791
|
+
"exports": [
|
|
1792
|
+
{
|
|
1793
|
+
"name": "Rating",
|
|
1794
|
+
"kind": "component",
|
|
1795
|
+
"description": {
|
|
1796
|
+
"primary": "jsdoc",
|
|
1797
|
+
"jsdoc": "Rating - Componente de calificación con estrellas\nComponente que muestra un sistema de calificación con estrellas.\nSoporta modo lectura y edición, hover interactivo y diferentes tamaños.",
|
|
1798
|
+
"confidence": "medium"
|
|
1799
|
+
},
|
|
1800
|
+
"examples": []
|
|
1801
|
+
}
|
|
1802
|
+
]
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
"id": "Separator",
|
|
1806
|
+
"path": "src/modules/Separator",
|
|
1807
|
+
"legacy": false,
|
|
1808
|
+
"compositionType": 1,
|
|
1809
|
+
"exports": [
|
|
1810
|
+
{
|
|
1811
|
+
"name": "Separator",
|
|
1812
|
+
"kind": "component",
|
|
1813
|
+
"description": {
|
|
1814
|
+
"primary": "storybook",
|
|
1815
|
+
"storybook": "Separador visual horizontal o vertical. Con",
|
|
1816
|
+
"jsdoc": "Separator - Componente de separador visual\nComponente que muestra una línea separadora horizontal o vertical.\nÚtil para dividir secciones de contenido visualmente.",
|
|
1817
|
+
"confidence": "high"
|
|
1818
|
+
},
|
|
1819
|
+
"examples": []
|
|
1820
|
+
}
|
|
1821
|
+
]
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
"id": "Sidebar",
|
|
1825
|
+
"path": "src/modules/Sidebar",
|
|
1826
|
+
"legacy": false,
|
|
1827
|
+
"compositionType": 1,
|
|
1828
|
+
"exports": [
|
|
1829
|
+
{
|
|
1830
|
+
"name": "Sidebar",
|
|
1831
|
+
"kind": "component",
|
|
1832
|
+
"description": {
|
|
1833
|
+
"primary": "storybook",
|
|
1834
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1835
|
+
"jsdoc": "Application sidebar aligned with the Sidebar-Menu Figma spec: 240px expanded, 56px collapsed,\n12px rail padding, header row (logo + optional trailing), collapse control with shadow-03,\nscrollable menu region, workspace card below the menu (or sheet over profile when `workspace.workspaceSheet`),\nthen profile and optional footer.",
|
|
1836
|
+
"confidence": "high"
|
|
1837
|
+
},
|
|
1838
|
+
"examples": []
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
"name": "SidebarMenuItem",
|
|
1842
|
+
"kind": "component",
|
|
1843
|
+
"description": {
|
|
1844
|
+
"primary": "storybook",
|
|
1845
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1846
|
+
"jsdoc": "============================================\nSIDEBAR MENU ITEM - ATOM\n============================================\nComponente atómico para items individuales del menú lateral.\nReutiliza el componente ListItemDefault del paquete UI.\nSoporta iconos, badges, estados activo/deshabilitado y submenús.",
|
|
1847
|
+
"confidence": "high"
|
|
1848
|
+
},
|
|
1849
|
+
"examples": []
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
"name": "SidebarDivider",
|
|
1853
|
+
"kind": "component",
|
|
1854
|
+
"description": {
|
|
1855
|
+
"primary": "storybook",
|
|
1856
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1857
|
+
"jsdoc": "============================================\nSIDEBAR DIVIDER - ATOM\n============================================\nSeparador para el sidebar. Puede ser una línea simple\no incluir un texto descriptivo.",
|
|
1858
|
+
"confidence": "high"
|
|
1859
|
+
},
|
|
1860
|
+
"examples": []
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
"name": "SidebarSectionTitle",
|
|
1864
|
+
"kind": "component",
|
|
1865
|
+
"description": {
|
|
1866
|
+
"primary": "storybook",
|
|
1867
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1868
|
+
"jsdoc": "============================================\nSIDEBAR SECTION TITLE - ATOM\n============================================\nSection label for the sidebar; groups menu blocks.\nBody XS Regular, tertiary, sentence case (no uppercase transform).",
|
|
1869
|
+
"confidence": "high"
|
|
1870
|
+
},
|
|
1871
|
+
"examples": []
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
"name": "SidebarMenuGroup",
|
|
1875
|
+
"kind": "component",
|
|
1876
|
+
"description": {
|
|
1877
|
+
"primary": "storybook",
|
|
1878
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1879
|
+
"jsdoc": "Groups menu rows under an optional section title (Figma section headers).\nWith `collapsible`, the header toggles the item list (chevron up/down).\nWhen `collapsed`, titled groups render a plain divider (unless skipped) and items only.",
|
|
1880
|
+
"confidence": "high"
|
|
1881
|
+
},
|
|
1882
|
+
"examples": []
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
"name": "SidebarUserProfile",
|
|
1886
|
+
"kind": "component",
|
|
1887
|
+
"description": {
|
|
1888
|
+
"primary": "storybook",
|
|
1889
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1890
|
+
"jsdoc": "Sidebar user rail (avatar, name, subtitle) with an optional account menu in a border popover\nwithout arrow (`popoverArrow={false}`), aligned with Sidebar-Menu Figma `290:52422`.",
|
|
1891
|
+
"confidence": "high"
|
|
1892
|
+
},
|
|
1893
|
+
"examples": []
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
"name": "SidebarWorkspaceCard",
|
|
1897
|
+
"kind": "component",
|
|
1898
|
+
"description": {
|
|
1899
|
+
"primary": "storybook",
|
|
1900
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1901
|
+
"jsdoc": "“Mesa de trabajo” surface for the sidebar rail (Figma Sidebar-Menu `_Storage Usage Widget`):\ngradient fill, dashed border, section label, icon + primary line + badge, divider, text CTAs.\nIcon + headline sit on one marquee track (vertically centered vs. badge); hover scrolls icon + title together (see `ui-sidebar-workspace-marquee-*` in shared styles).",
|
|
1902
|
+
"confidence": "high"
|
|
1903
|
+
},
|
|
1904
|
+
"examples": []
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
"name": "SidebarDrilldownPanel",
|
|
1908
|
+
"kind": "component",
|
|
1909
|
+
"description": {
|
|
1910
|
+
"primary": "storybook",
|
|
1911
|
+
"storybook": "El componente Sidebar sigue el marco Sidebar-Menu (Figma): 240px / 56px, padding 12px, cabecera con slot, lista scroll, tarjeta workspace (borde dashed), perfil y pie. Incluye secciones colapsables, drilldown y avatar compacto al colapsar.",
|
|
1912
|
+
"jsdoc": "Second-level sidebar region: back control, optional breadcrumb, and submenu rows.\nPresentation-only: routing and `href` handling belong to the host via `onActivateSubmenu`.",
|
|
1913
|
+
"confidence": "high"
|
|
1914
|
+
},
|
|
1915
|
+
"examples": []
|
|
1916
|
+
}
|
|
1917
|
+
]
|
|
1918
|
+
},
|
|
1919
|
+
{
|
|
1920
|
+
"id": "Skeleton",
|
|
1921
|
+
"path": "src/modules/Skeleton",
|
|
1922
|
+
"legacy": false,
|
|
1923
|
+
"compositionType": 1,
|
|
1924
|
+
"exports": [
|
|
1925
|
+
{
|
|
1926
|
+
"name": "Skeleton",
|
|
1927
|
+
"kind": "component",
|
|
1928
|
+
"description": {
|
|
1929
|
+
"primary": "jsdoc",
|
|
1930
|
+
"jsdoc": "Skeleton - Componente de placeholder de carga\nComponente que muestra un placeholder animado mientras se carga el contenido.\nÚtil para mejorar la experiencia de usuario durante la carga de datos.",
|
|
1931
|
+
"confidence": "medium"
|
|
1932
|
+
},
|
|
1933
|
+
"examples": []
|
|
1934
|
+
}
|
|
1935
|
+
]
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
"id": "Spinner",
|
|
1939
|
+
"path": "src/modules/Spinner",
|
|
1940
|
+
"legacy": false,
|
|
1941
|
+
"compositionType": 1,
|
|
1942
|
+
"exports": [
|
|
1943
|
+
{
|
|
1944
|
+
"name": "Spinner",
|
|
1945
|
+
"kind": "component",
|
|
1946
|
+
"description": {
|
|
1947
|
+
"primary": "storybook",
|
|
1948
|
+
"storybook": "El componente Spinner permite mostrar un spinner de carga.",
|
|
1949
|
+
"jsdoc": "Spinner - Componente de spinner de carga animado\nComponente que muestra una animación de carga usando Lottie.\nÚtil para indicar que una operación está en progreso.",
|
|
1950
|
+
"confidence": "high"
|
|
1951
|
+
},
|
|
1952
|
+
"examples": [
|
|
1953
|
+
"import { Spinner } from '@imj_media/ui';\n\n export default function Example() {\n return <Spinner />\n }",
|
|
1954
|
+
"import { Spinner } from '@imj_media/ui';\n\n export default function Example() {\n return <Spinner />\n }"
|
|
1955
|
+
]
|
|
1956
|
+
}
|
|
1957
|
+
]
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
"id": "Stepper",
|
|
1961
|
+
"path": "src/modules/Stepper",
|
|
1962
|
+
"legacy": false,
|
|
1963
|
+
"compositionType": 1,
|
|
1964
|
+
"exports": [
|
|
1965
|
+
{
|
|
1966
|
+
"name": "Stepper",
|
|
1967
|
+
"kind": "component",
|
|
1968
|
+
"description": {
|
|
1969
|
+
"primary": "jsdoc",
|
|
1970
|
+
"jsdoc": "Variantes del Stepper usando tokens semánticos\n/\nconst stepperVariants = cva('', {\n variants: {\n color: {\n blue: '',\n red: '',\n green: '',\n orange: '',\n yellow: '',\n 'blue-dark': '',\n 'blue-light': '',\n neutral: '',\n white: '',\n black: '',\n transparent: '',\n },\n size: {\n xs: '',\n sm: '',\n md: '',\n lg: '',\n },\n },\n defaultVariants: {\n color: 'blue',\n size: 'md',\n },\n});\n\n/**\nStepper - Componente de pasos/progreso de pasos\nComponente que muestra un conjunto de pasos con indicadores de estado (completado, activo, pendiente).\nSoporta orientación horizontal y vertical, múltiples colores y tamaños.",
|
|
1971
|
+
"confidence": "medium"
|
|
1972
|
+
},
|
|
1973
|
+
"examples": [
|
|
1974
|
+
"import { Stepper } from \"@imj_me/ui\";\n import { useState } from \"react\";\n\n const [currentStep, setCurrentStep] = useState(0);\n\n function Example() {\n return (\n <Stepper\n steps={steps}\n currentStep={currentStep}\n onStepChange={setCurrentStep}\n />\n );\n }",
|
|
1975
|
+
"import { Stepper } from \"@imj_me/ui\";\n\n const steps = [{}, {}, {}, {}];\n\n <Stepper steps={steps} currentStep={currentStep} onStepChange={setCurrentStep} className=\"ui-w-full\" />",
|
|
1976
|
+
"// El conector horizontal escala con el ancho de cada celda (flex-1 + min-width del paso).\n // Envuelve el Stepper en un contenedor con ancho conocido o responsive.\n\n <div className=\"ui-w-full ui-max-w-3xl\">\n <Stepper\n steps={steps}\n currentStep={currentStep}\n onStepChange={setCurrentStep}\n withScroll={false}\n className=\"ui-w-full\"\n />\n </div>",
|
|
1977
|
+
"<Stepper\n steps={steps}\n currentStep={currentStep}\n onStepChange={setCurrentStep}\n stepClickable\n />",
|
|
1978
|
+
"<Stepper\n steps={steps}\n currentStep={currentStep}\n onStepChange={setCurrentStep}\n vertical\n />"
|
|
1979
|
+
]
|
|
1980
|
+
}
|
|
1981
|
+
]
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
"id": "StoryBox",
|
|
1985
|
+
"path": "src/modules/StoryBox",
|
|
1986
|
+
"legacy": false,
|
|
1987
|
+
"compositionType": 1,
|
|
1988
|
+
"exports": [
|
|
1989
|
+
{
|
|
1990
|
+
"name": "StoryBox",
|
|
1991
|
+
"kind": "component",
|
|
1992
|
+
"description": {
|
|
1993
|
+
"primary": "jsdoc",
|
|
1994
|
+
"jsdoc": "Tema Orbit efectivo para hijos (`auto` en código): forzado por `StoryBox` o el `data-theme` de `documentElement`. */\ntype StoryBoxOrbitAppearance = 'light' | 'dark';\n\nconst StoryBoxForcedAppearanceContext = createContext<StoryBoxOrbitAppearance | null>(null);\n\nfunction getDocumentThemeSnapshot(): StoryBoxOrbitAppearance {\n if (typeof document === 'undefined') return 'light';\n return document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';\n}\n\nfunction subscribeDocumentTheme(onStoreChange: () => void): () => void {\n if (typeof document === 'undefined') return () => {};\n const el = document.documentElement;\n const mo = new MutationObserver(onStoreChange);\n mo.observe(el, { attributes: true, attributeFilter: ['data-theme'] });\n return () => mo.disconnect();\n}",
|
|
1995
|
+
"confidence": "medium"
|
|
1996
|
+
},
|
|
1997
|
+
"examples": [
|
|
1998
|
+
"import { StoryBox, Button } from '@imj_media/ui';\n\nexport function Ejemplo() {\n return (\n <StoryBox appearance=\"dark\">\n <StoryBox.Title>Título</StoryBox.Title>\n <StoryBox.Content>\n <Button variant=\"button\">Acción</Button>\n </StoryBox.Content>\n </StoryBox>\n );\n}",
|
|
1999
|
+
"import { StoryBox } from '@/modules/StoryBox';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n return (\n <StoryBox>\n <StoryBox.Title>StoryBox Básico</StoryBox.Title>\n <StoryBox.Description>StoryBox simple con configuración por defecto</StoryBox.Description>\n <StoryBox.Content>\n <Button variant=\"button\">Click me</Button>\n </StoryBox.Content>\n <StoryBox.Code language=\"tsx\">\n <Button variant=\"button\">Click me</Button>\n </StoryBox.Code>\n </StoryBox>\n )\n }",
|
|
2000
|
+
"import { StoryBox, Button } from '@imj_media/ui';\n\nexport function Ejemplo() {\n return (\n <StoryBox appearance=\"dark\">\n <StoryBox.Title>Título</StoryBox.Title>\n <StoryBox.Content>\n <Button variant=\"button\">Acción</Button>\n </StoryBox.Content>\n </StoryBox>\n );\n}",
|
|
2001
|
+
"import { StoryBox } from '@/modules/StoryBox';\n import { Button } from '@/modules/Button';\n\n export default function Example() {\n return (\n <StoryBox>\n <StoryBox.Title>StoryBox Básico</StoryBox.Title>\n <StoryBox.Description>StoryBox simple con configuración por defecto</StoryBox.Description>\n <StoryBox.Content>\n <Button variant=\"button\">Click me</Button>\n </StoryBox.Content>\n <StoryBox.Code language=\"tsx\">\n <Button variant=\"button\">Click me</Button>\n </StoryBox.Code>\n </StoryBox>\n )\n }"
|
|
2002
|
+
]
|
|
2003
|
+
}
|
|
2004
|
+
]
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
"id": "Switch",
|
|
2008
|
+
"path": "src/modules/Switch",
|
|
2009
|
+
"legacy": false,
|
|
2010
|
+
"compositionType": 1,
|
|
2011
|
+
"exports": [
|
|
2012
|
+
{
|
|
2013
|
+
"name": "Switch",
|
|
2014
|
+
"kind": "component",
|
|
2015
|
+
"description": {
|
|
2016
|
+
"primary": "jsdoc",
|
|
2017
|
+
"jsdoc": "Tipografía del label en control `md`: tamaño/interlineado/tracking Regular + peso Bold (spec Type/Body/SM). */\nconst SWITCH_MD_LABEL_TYPOGRAPHY =\n 'ui-text-body-sm-regular ui-font-body-sm-bold ui-leading-body-sm-regular ui-tracking-body-sm';\n\nfunction optionSlotToButtonSlotConfig(\n icon: SwitchOption['leftSlot'],\n colorIcon: IconFontColor | undefined,\n duotone: Pick<\n ButtonSlotConfig,\n | 'iconDuotonePrimary'\n | 'iconDuotoneSecondary'\n | 'iconDuotoneOpacityPrimary'\n | 'iconDuotoneOpacitySecondary'\n >,\n defaultIconFontSize: IconFontSize,\n optionIconFontSize?: IconFontSize,\n): ButtonSlotConfig | undefined {\n if (icon === null || icon === undefined) {\n return undefined;\n }\n return {\n icon,\n ...(colorIcon !== undefined ? { colorIcon } : {}),\n ...duotone,",
|
|
2018
|
+
"confidence": "medium"
|
|
2019
|
+
},
|
|
2020
|
+
"examples": [
|
|
2021
|
+
"import { Switch, SwitchOption } from '@/modules/Switch';\n\n const options: SwitchOption[] = [\n { label: \"Acordeón 1\", value: \"accordion-1\", leftSlot: faSlash, rightSlot: faFolder },\n { label: \"Acordeón 2\", value: \"accordion-2\", leftSlot: faSlash, rightSlot: faCalendar },\n { label: \"Acordeón 3\", value: \"accordion-3\", leftSlot: faSlash, rightSlot: faCarrot },\n ]\n \n export default function Example() {\n return <Switch options={options} defaultValue=\"accordion-1\" onChange={(value) => {\n console.log(value);\n }} />\n }",
|
|
2022
|
+
"import { Switch, SwitchOption } from '@/modules/Switch';\n\n const options: SwitchOption[] = [\n { label: \"Disponible A\", value: \"a\", leftSlot: faList, rightSlot: faSquare },\n { label: \"No disponible\", value: \"b\", leftSlot: faClock, rightSlot: faXmark, disabled: true },\n { label: \"Disponible C\", value: \"c\", leftSlot: faCheck, rightSlot: faEdit },\n ];\n\n export default function Example() {\n return (\n <Switch\n options={options}\n defaultValue=\"a\"\n onChange={(value) => console.log(value)}\n />\n );\n }",
|
|
2023
|
+
"import { Switch, SwitchOption } from '@/modules/Switch';\n\n const options: SwitchOption[] = [\n { label: \"Acordeón 1\", value: \"accordion-1\", leftSlot: faSlash, rightSlot: faFolder },\n { label: \"Acordeón 2\", value: \"accordion-2\", leftSlot: faSlash, rightSlot: faCalendar },\n { label: \"Acordeón 3\", value: \"accordion-3\", leftSlot: faSlash, rightSlot: faCarrot }\n ]\n \n export default function Example() {\n return <div className=\"ui-flex ui-flex-col ui-gap-2\">\n <Switch options={options} defaultValue=\"accordion-1\" size=\"xs\" onChange={(value) => {\n console.log(value);\n }} />\n <Switch options={options} defaultValue=\"accordion-2\" size=\"sm\" onChange={(value) => {\n console.log(value);\n }} />\n <Switch options={options} defaultValue=\"accordion-3\" size=\"md\" onChange={(value) => {\n console.log(value);\n }} />\n </div>\n }",
|
|
2024
|
+
"import { Switch, SwitchOption } from '@/modules/Switch';\n\n const options: SwitchOption[] = [\n { label: \"Vista Lista\", value: \"list\", leftSlot: faList },\n { label: \"Vista Grid\", value: \"grid\", leftSlot: faSquare },\n { label: \"Vista Calendario\", value: \"calendar\", leftSlot: faCalendar }\n ]\n \n export default function Example() {\n return <Switch options={options} defaultValue=\"list\" onChange={(value) => {\n console.log(value);\n }} />\n }",
|
|
2025
|
+
"import { Switch, SwitchOption } from '@/modules/Switch';\n\n const options: SwitchOption[] = [\n { label: \"Activo\", value: \"active\", rightSlot: faCheck },\n { label: \"Inactivo\", value: \"inactive\", rightSlot: faXmark },\n { label: \"Pendiente\", value: \"pending\", rightSlot: faClock }\n ]\n \n export default function Example() {\n return <Switch options={options} defaultValue=\"active\" onChange={(value) => {\n console.log(value);\n }} />\n }"
|
|
2026
|
+
]
|
|
2027
|
+
}
|
|
2028
|
+
]
|
|
2029
|
+
},
|
|
2030
|
+
{
|
|
2031
|
+
"id": "Table",
|
|
2032
|
+
"path": "src/modules/Table",
|
|
2033
|
+
"legacy": false,
|
|
2034
|
+
"compositionType": 1,
|
|
2035
|
+
"exports": [
|
|
2036
|
+
{
|
|
2037
|
+
"name": "Table",
|
|
2038
|
+
"kind": "component",
|
|
2039
|
+
"description": {
|
|
2040
|
+
"primary": "storybook",
|
|
2041
|
+
"storybook": "Prop",
|
|
2042
|
+
"readme": "# Table Component\n\nComponente de tabla completo y altamente configurable con soporte para múltiples funcionalidades empresariales.\n\n## 📚 Documentación\n\n- **[Ver Ejemplo de Uso Completo](./EJEMPLO_USO.md)** - Guía detallada con todos los casos de uso\n- **[Celda `imagePreview`](./IMAGE_PREVIEW_CELL.md)** - Columna con miniatura y popup al hover\n- **[Personalización `imagePreview`](./IMAGE_PREVIEW_CUSTOMIZATION.md)** - Qué se puede ajustar y qué es fijo (aspecto, padding, bordes)\n- **[Ver Stories en Storybook](./stories/Table.stories.tsx)** - Ejemplos interactivos\n\n## ✨ Características\n\n- ✅ **Tipos de celdas múltiples**: Default, Primary, Status, Actions, Link, Avatars, TextField, Dropdown, Button, Progress Bar, Skeleton, Tags, Checkbox, Icon, Stars\n- ✅ **Ordenamiento**: Sorting por columnas con indicadores visuales\n- ✅ **Filtrado**: Múltiples filtros por columna\n- ✅ **Búsqueda global**: Búsqueda en tiempo real en todas las columnas\n- ✅ **Selección**: Selección simple o múltiple de filas con callbacks\n- ✅ **Paginación**: Paginación completa con tamaños configurables\n- ✅ **Toolbar**: Barra de herramientas con búsqueda, filtros, exportación y configuración de columnas\n- ✅ **Estados de carga**: Skeleton loading states\n- ✅ **Estados vacíos**: Personalización de vistas vacías y sin resultados\n- ✅ **Filas expandibles**: Parent/child rows con animaciones\n- ✅ **Columnas bloqueables**: Sticky columns\n- ✅ **Columnas redimensionables**: Resize columns por arrastre o doble click para auto-ajustar\n- ✅ **Responsive**: Diseño adaptable\n- ✅ **Accesibilidad**: Soporte completo ARIA y navegación por teclado\n- ✅ **TypeScript**: Totalmente tipado\n\n## Estructura del Módulo\n\n```\nTable/\n├── components/\n│ ├── atoms/ # Componentes atómicos (celdas)\n│ ├── molecules/ # HeaderCell, TableRow, CellRenderer\n│ └── organisms/ # TableToolbar, TableHeader, TableBody, TableContent\n├── hooks/\n│ ├── useTableSort.ts\n│ ├── useTableFilter.ts\n│ ├── useTableSelection.",
|
|
2043
|
+
"confidence": "high"
|
|
2044
|
+
},
|
|
2045
|
+
"examples": [
|
|
2046
|
+
"<Table\n columns={columns}\n rows={rows}\n selection={{ enabled: true, multiple: true }}\n excludedRows={{\n excludeKey: 'estado',\n rows: ['archivado', 'bloqueado'],\n }}\n/>",
|
|
2047
|
+
"<Table\n columns={columns}\n rows={rows}\n selection={{ enabled: true, multiple: true }}\n excludedRows={{\n excludeKey: 'estado',\n rows: ['archivado', 'bloqueado'],\n }}\n/>",
|
|
2048
|
+
"import { SelectionCheckbox } from '@/modules/Table/components/molecules/SelectionCheckbox';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [checked, setChecked] = useState(false);\n \n return (\n <>\n <SelectionCheckbox\n checked={checked}\n onChange={setChecked}\n />\n <SelectionCheckbox\n checked={true}\n onChange={() => {}}\n />\n <SelectionCheckbox\n checked={false}\n indeterminate={true}\n onChange={() => {}}\n />\n </>\n );\n}",
|
|
2049
|
+
"import { SelectionCheckbox } from '@/modules/Table/components/molecules/SelectionCheckbox';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [checked, setChecked] = useState(false);\n \n return (\n <>\n <SelectionCheckbox\n checked={checked}\n onChange={setChecked}\n round={true}\n />\n <SelectionCheckbox\n checked={true}\n onChange={() => {}}\n round={true}\n />\n <SelectionCheckbox\n checked={false}\n indeterminate={true}\n onChange={() => {}}\n round={true}\n />\n </>\n );\n}",
|
|
2050
|
+
"import { SelectionCheckbox } from '@/modules/Table/components/molecules/SelectionCheckbox';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [checked1, setChecked1] = useState(false);\n const [checked2, setChecked2] = useState(false);\n \n return (\n <>\n {/* Cuadrado (por defecto) */}\n <SelectionCheckbox\n checked={checked1}\n onChange={setChecked1}\n round={false}\n />\n \n {/* Redondo */}\n <SelectionCheckbox\n checked={checked2}\n onChange={setChecked2}\n round={true}\n />\n </>\n );\n}",
|
|
2051
|
+
"import { SelectionCheckbox } from '@/modules/Table/components/molecules/SelectionCheckbox';\n\nexport default function Example() {\n return (\n <>\n {/* Cuadrado - No marcado */}\n <SelectionCheckbox\n checked={false}\n onChange={() => {}}\n round={false}\n />\n \n {/* Cuadrado - Marcado */}\n <SelectionCheckbox\n checked={true}\n onChange={() => {}}\n round={false}\n />\n \n {/* Redondo - No marcado */}\n <SelectionCheckbox\n checked={false}\n onChange={() => {}}\n round={true}\n />\n \n {/* Redondo - Marcado */}\n <SelectionCheckbox\n checked={true}\n onChange={() => {}}\n round={true}\n />\n </>\n );\n}",
|
|
2052
|
+
"import { SelectionCheckbox } from '@/modules/Table/components/molecules/SelectionCheckbox';\nimport { useState } from 'react';\n\nexport default function Example() {\n const [checked, setChecked] = useState(false);\n \n return (\n <>\n <SelectionCheckbox\n checked={checked}\n onChange={setChecked}\n />\n <SelectionCheckbox\n checked={true}\n onChange={() => {}}\n />\n <SelectionCheckbox\n checked={false}\n indeterminate={true}\n onChange={() => {}}\n />\n </>\n );\n}",
|
|
2053
|
+
"const columnasConAcciones = [\n {\n id: 'actions',\n header: 'Acciones',\n type: 'actions',\n render: (_: unknown, row: User): TableActionConfig<User>[] => [\n {\n icon: faPen,\n tooltip: 'Editar',\n onClick: (r: User) => console.log('Editar', r),\n },\n {\n icon: faTrash,\n tooltip: 'Eliminar',\n onClick: (r: User) => console.log('Eliminar', r),\n },\n {\n icon: faEye,\n tooltip: 'Ver',\n onClick: (r: User) => console.log('Ver', r),\n },\n ],\n },\n]\n\n<Table\n columns={columnasConAcciones}\n rows={rows}\n hoverable={true}\n/>",
|
|
2054
|
+
"import { Table } from '@imj_media/ui';\nimport { ColumnConfig } from '@/shared/types/table';\n\ninterface AlignmentData {\n id: number;\n name: string;\n amount: number;\n status: string;\n progress: number;\n date: Date;\n tags: string[];\n}\n\nconst columns: ColumnConfig<AlignmentData>[] = [\n {\n id: 'id',\n header: 'ID',\n accessor: 'id',\n contentAlign: 'left', // Por defecto\n },\n {\n id: 'name',\n header: 'Nombre',\n accessor: 'name',\n contentAlign: 'left', // Texto alineado a la izquierda\n },\n {\n id: 'amount',\n header: 'Monto',\n accessor: 'amount',\n contentAlign: 'right', // Números alineados a la derecha\n render: (value: number) => \\",
|
|
2055
|
+
"<Table\n columns={columns}\n rows={rows}\n hoverable={true}\n/>",
|
|
2056
|
+
"<Table\n columns={columns}\n rows={rows}\n bordered={true}\n hoverable={true}\n/>",
|
|
2057
|
+
"<Table\n columns={columns}\n rows={rows}\n toolbar={{\n showSearch: true,\n searchPlaceholder: 'Buscar por nombre, correo, rol, estado...',\n searchWidth: 360,\n }}\n/>",
|
|
2058
|
+
"const columns: ColumnConfig<MisDatos>[] = [\n { id: 'nombre', header: 'Nombre', accessor: 'nombre', sortable: true },\n // …sin repetir lockable en cada una\n];\n\n<Table\n columns={columns}\n rows={rows}\n columnsLockable={false}\n toolbar={{ showColumnConfig: true }}\n resizable\n/>",
|
|
2059
|
+
"<Table\n columns={[\n { id: 'id', header: 'ID', accessor: 'id', lockable: true },\n { id: 'nombre', header: 'Nombre', accessor: 'nombre' },\n ]}\n columnsLockable={false}\n rows={rows}\n/>",
|
|
2060
|
+
"const columns: ColumnConfig<MisDatos>[] = [\n { id: 'nombre', header: 'Nombre', accessor: 'nombre', sortable: true },\n // …sin repetir lockable en cada una\n];\n\n<Table\n columns={columns}\n rows={rows}\n columnsLockable={false}\n toolbar={{ showColumnConfig: true }}\n resizable\n/>",
|
|
2061
|
+
"<Table\n columns={[\n { id: 'id', header: 'ID', accessor: 'id', lockable: true },\n { id: 'nombre', header: 'Nombre', accessor: 'nombre' },\n ]}\n columnsLockable={false}\n rows={rows}\n/>",
|
|
2062
|
+
"import { Table } from '@/modules/Table';\n\n// Persistir columnas, orden, filtros y búsqueda en la misma key de localStorage\n<Table<Persona>\n columns={columnas}\n rows={filas}\n configKey=\"mi-tabla\"\n persistConfig={true}\n queryPersist={true}\n toolbar={{\n showSearch: true,\n searchPlaceholder: 'Buscar...',\n internalSearch: true,\n showFilters: true,\n internalFilters: true,\n showColumnConfig: true,\n }}\n onConfigChange={(config, changeType) => console.log(changeType, config)}\n striped\n hoverable\n resizable\n/>\n\n// queryPersist={false} → no se guardan ni restauran búsqueda ni filtros (solo columnas/orden)",
|
|
2063
|
+
"import { Table } from '@/modules/Table';\n\n// Persistir columnas, orden, filtros y búsqueda en la misma key de localStorage\n<Table<Persona>\n columns={columnas}\n rows={filas}\n configKey=\"mi-tabla\"\n persistConfig={true}\n queryPersist={true}\n toolbar={{\n showSearch: true,\n searchPlaceholder: 'Buscar...',\n internalSearch: true,\n showFilters: true,\n internalFilters: true,\n showColumnConfig: true,\n }}\n onConfigChange={(config, changeType) => console.log(changeType, config)}\n striped\n hoverable\n resizable\n/>\n\n// queryPersist={false} → no se guardan ni restauran búsqueda ni filtros (solo columnas/orden)",
|
|
2064
|
+
"<Table\n columns={columns}\n rows={pageRows}\n selection={{\n enabled: true,\n multiple: true,\n showSelectionBar: true,\n actions: [{ label: 'Eliminar', onClick: (ids) => { ... } }],\n }}\n pagination={{\n enabled: true,\n currentPage: page,\n pageSize,\n total: totalRowCount,\n onPageChange: setPage,\n onPageSizeChange: setPageSize,\n }}\n/>",
|
|
2065
|
+
"<Table\n columns={columns}\n rows={pageRows}\n selection={{\n enabled: true,\n multiple: true,\n showSelectionBar: true,\n actions: [{ label: 'Eliminar', onClick: (ids) => { ... } }],\n }}\n pagination={{\n enabled: true,\n currentPage: page,\n pageSize,\n total: totalRowCount,\n onPageChange: setPage,\n onPageSizeChange: setPageSize,\n }}\n/>"
|
|
2066
|
+
]
|
|
2067
|
+
}
|
|
2068
|
+
]
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
"id": "Tag",
|
|
2072
|
+
"path": "src/modules/Tag",
|
|
2073
|
+
"legacy": false,
|
|
2074
|
+
"compositionType": 1,
|
|
2075
|
+
"exports": [
|
|
2076
|
+
{
|
|
2077
|
+
"name": "Tag",
|
|
2078
|
+
"kind": "component",
|
|
2079
|
+
"description": {
|
|
2080
|
+
"primary": "storybook",
|
|
2081
|
+
"storybook": "El componente Tag permite mostrar etiquetas, filtros o categorías con diferentes colores. Icono a la izquierda opcional vía",
|
|
2082
|
+
"jsdoc": "Tag - Componente de etiqueta/tag versátil y configurable\nComponente de tag que soporta múltiples colores, estados (selected, disabled),\navatares, iconos de cierre e información, y diferentes estilos visuales.",
|
|
2083
|
+
"confidence": "high"
|
|
2084
|
+
},
|
|
2085
|
+
"examples": [
|
|
2086
|
+
"import { Tag } from '@imj_media/ui';\n\n export default function Example() {\n return (\n <>\n <Tag label=\"Etiqueta\" color=\"accent\" />\n <Tag label=\"Categoría\" color=\"accent\" />\n <Tag label=\"Filtro\" color=\"accent\" />\n </>\n )\n }",
|
|
2087
|
+
"<Tag label=\"Accent\" color=\"accent\" />\n <Tag label=\"Gray\" color=\"gray\" />\n <Tag label=\"Success\" color=\"success\" />\n <Tag label=\"Warning\" color=\"warning\" />\n <Tag label=\"Danger\" color=\"danger\" />\n <Tag label=\"Info\" color=\"info\" />\n <Tag label=\"Disabled\" color=\"disabled\" />",
|
|
2088
|
+
"<Tag label=\"Accent\" color=\"accent\" stroke={true} />\n <Tag label=\"Success\" color=\"success\" stroke={false} />",
|
|
2089
|
+
"import { faCircleInfo } from '@fortawesome/pro-regular-svg-icons';\n\n <Tag label=\"Info\" color=\"info\" infoIcon={{ name: faCircleInfo }} />\n <Tag label=\"Success\" color=\"success\" infoIcon={{ name: faCircleInfo }} />",
|
|
2090
|
+
"import {\n faCircleInfo,\n faFilter,\n faSearch,\n } from '@fortawesome/pro-regular-svg-icons';\n\n <Tag\n label='\"query\"'\n color=\"success\"\n infoIcon={{ name: faSearch }}\n onClose={() => {}}\n />\n <Tag\n label=\"Custom\"\n color=\"info\"\n infoIcon={{ name: faCircleInfo, size: 'sm', color: 'warning' }}\n />"
|
|
2091
|
+
]
|
|
2092
|
+
}
|
|
2093
|
+
]
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
"id": "Text",
|
|
2097
|
+
"path": "src/modules/Text",
|
|
2098
|
+
"legacy": false,
|
|
2099
|
+
"compositionType": 1,
|
|
2100
|
+
"exports": [
|
|
2101
|
+
{
|
|
2102
|
+
"name": "Text",
|
|
2103
|
+
"kind": "component",
|
|
2104
|
+
"description": {
|
|
2105
|
+
"primary": "storybook",
|
|
2106
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2107
|
+
"jsdoc": "Text - Componente de texto versátil con múltiples variantes tipográficas\nComponente que renderiza texto con diferentes tipos tipográficos (body, title, caption, code)\ny tamaños. Soporta pesos de fuente personalizados y colores.",
|
|
2108
|
+
"confidence": "high"
|
|
2109
|
+
},
|
|
2110
|
+
"examples": [
|
|
2111
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2112
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2113
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2114
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2115
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2116
|
+
]
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
"name": "Body",
|
|
2120
|
+
"kind": "component",
|
|
2121
|
+
"description": {
|
|
2122
|
+
"primary": "storybook",
|
|
2123
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2124
|
+
"confidence": "medium"
|
|
2125
|
+
},
|
|
2126
|
+
"examples": [
|
|
2127
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2128
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2129
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2130
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2131
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2132
|
+
],
|
|
2133
|
+
"props": {
|
|
2134
|
+
"groups": {},
|
|
2135
|
+
"deprecatedRoot": [
|
|
2136
|
+
{
|
|
2137
|
+
"name": "textColor",
|
|
2138
|
+
"type": "TextColor"
|
|
2139
|
+
}
|
|
2140
|
+
],
|
|
2141
|
+
"flat": {
|
|
2142
|
+
"size": {
|
|
2143
|
+
"name": "size",
|
|
2144
|
+
"type": "BodySize | BaseSize",
|
|
2145
|
+
"required": false,
|
|
2146
|
+
"description": "Tamaño del body: xs, sm, md, lg o tamaños base"
|
|
2147
|
+
},
|
|
2148
|
+
"weight": {
|
|
2149
|
+
"name": "weight",
|
|
2150
|
+
"type": "TextWeight",
|
|
2151
|
+
"required": false,
|
|
2152
|
+
"description": "Peso de la fuente"
|
|
2153
|
+
},
|
|
2154
|
+
"children": {
|
|
2155
|
+
"name": "children",
|
|
2156
|
+
"type": "React.ReactNode",
|
|
2157
|
+
"required": true,
|
|
2158
|
+
"description": "Contenido del texto"
|
|
2159
|
+
},
|
|
2160
|
+
"className": {
|
|
2161
|
+
"name": "className",
|
|
2162
|
+
"type": "string",
|
|
2163
|
+
"required": false,
|
|
2164
|
+
"description": "Clase CSS adicional"
|
|
2165
|
+
},
|
|
2166
|
+
"as": {
|
|
2167
|
+
"name": "as",
|
|
2168
|
+
"type": "keyof JSX.IntrinsicElements",
|
|
2169
|
+
"required": false,
|
|
2170
|
+
"description": "Elemento HTML a renderizar (por defecto: span)"
|
|
2171
|
+
},
|
|
2172
|
+
"color": {
|
|
2173
|
+
"name": "color",
|
|
2174
|
+
"type": "TextColor | (string & {})",
|
|
2175
|
+
"required": false,
|
|
2176
|
+
"description": "Color del texto: puede ser un color del sistema de diseño o un color CSS personalizado"
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
},
|
|
2181
|
+
{
|
|
2182
|
+
"name": "Caption",
|
|
2183
|
+
"kind": "component",
|
|
2184
|
+
"description": {
|
|
2185
|
+
"primary": "storybook",
|
|
2186
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2187
|
+
"confidence": "medium"
|
|
2188
|
+
},
|
|
2189
|
+
"examples": [
|
|
2190
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2191
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2192
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2193
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2194
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2195
|
+
],
|
|
2196
|
+
"props": {
|
|
2197
|
+
"groups": {},
|
|
2198
|
+
"deprecatedRoot": [
|
|
2199
|
+
{
|
|
2200
|
+
"name": "textColor",
|
|
2201
|
+
"type": "TextColor"
|
|
2202
|
+
}
|
|
2203
|
+
],
|
|
2204
|
+
"flat": {
|
|
2205
|
+
"size": {
|
|
2206
|
+
"name": "size",
|
|
2207
|
+
"type": "CaptionSize | BaseSize",
|
|
2208
|
+
"required": false,
|
|
2209
|
+
"description": "Tamaño del caption: xs, md o tamaños base"
|
|
2210
|
+
},
|
|
2211
|
+
"weight": {
|
|
2212
|
+
"name": "weight",
|
|
2213
|
+
"type": "TextWeight",
|
|
2214
|
+
"required": false,
|
|
2215
|
+
"description": "Peso de la fuente (solo aplica si se usa tamaño base)"
|
|
2216
|
+
},
|
|
2217
|
+
"children": {
|
|
2218
|
+
"name": "children",
|
|
2219
|
+
"type": "React.ReactNode",
|
|
2220
|
+
"required": true,
|
|
2221
|
+
"description": "Contenido del texto"
|
|
2222
|
+
},
|
|
2223
|
+
"className": {
|
|
2224
|
+
"name": "className",
|
|
2225
|
+
"type": "string",
|
|
2226
|
+
"required": false,
|
|
2227
|
+
"description": "Clase CSS adicional"
|
|
2228
|
+
},
|
|
2229
|
+
"as": {
|
|
2230
|
+
"name": "as",
|
|
2231
|
+
"type": "keyof JSX.IntrinsicElements",
|
|
2232
|
+
"required": false,
|
|
2233
|
+
"description": "Elemento HTML a renderizar (por defecto: span)"
|
|
2234
|
+
},
|
|
2235
|
+
"color": {
|
|
2236
|
+
"name": "color",
|
|
2237
|
+
"type": "TextColor | (string & {})",
|
|
2238
|
+
"required": false,
|
|
2239
|
+
"description": "Color del texto: puede ser un color del sistema de diseño o un color CSS personalizado"
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
"name": "TitleText",
|
|
2246
|
+
"kind": "component",
|
|
2247
|
+
"description": {
|
|
2248
|
+
"primary": "storybook",
|
|
2249
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2250
|
+
"confidence": "medium"
|
|
2251
|
+
},
|
|
2252
|
+
"examples": [
|
|
2253
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2254
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2255
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2256
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2257
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2258
|
+
]
|
|
2259
|
+
},
|
|
2260
|
+
{
|
|
2261
|
+
"name": "Code",
|
|
2262
|
+
"kind": "component",
|
|
2263
|
+
"description": {
|
|
2264
|
+
"primary": "storybook",
|
|
2265
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2266
|
+
"confidence": "medium"
|
|
2267
|
+
},
|
|
2268
|
+
"examples": [
|
|
2269
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2270
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2271
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2272
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2273
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2274
|
+
],
|
|
2275
|
+
"props": {
|
|
2276
|
+
"groups": {},
|
|
2277
|
+
"deprecatedRoot": [
|
|
2278
|
+
{
|
|
2279
|
+
"name": "textColor",
|
|
2280
|
+
"type": "TextColor"
|
|
2281
|
+
}
|
|
2282
|
+
],
|
|
2283
|
+
"flat": {
|
|
2284
|
+
"size": {
|
|
2285
|
+
"name": "size",
|
|
2286
|
+
"type": "CodeSize | BaseSize",
|
|
2287
|
+
"required": false,
|
|
2288
|
+
"description": "Tamaño del code: md o tamaños base"
|
|
2289
|
+
},
|
|
2290
|
+
"weight": {
|
|
2291
|
+
"name": "weight",
|
|
2292
|
+
"type": "TextWeight",
|
|
2293
|
+
"required": false,
|
|
2294
|
+
"description": "Peso de la fuente (solo aplica si se usa tamaño base)"
|
|
2295
|
+
},
|
|
2296
|
+
"children": {
|
|
2297
|
+
"name": "children",
|
|
2298
|
+
"type": "React.ReactNode",
|
|
2299
|
+
"required": true,
|
|
2300
|
+
"description": "Contenido del código"
|
|
2301
|
+
},
|
|
2302
|
+
"className": {
|
|
2303
|
+
"name": "className",
|
|
2304
|
+
"type": "string",
|
|
2305
|
+
"required": false,
|
|
2306
|
+
"description": "Clase CSS adicional"
|
|
2307
|
+
},
|
|
2308
|
+
"as": {
|
|
2309
|
+
"name": "as",
|
|
2310
|
+
"type": "keyof JSX.IntrinsicElements",
|
|
2311
|
+
"required": false,
|
|
2312
|
+
"description": "Elemento HTML a renderizar (por defecto: code)"
|
|
2313
|
+
},
|
|
2314
|
+
"color": {
|
|
2315
|
+
"name": "color",
|
|
2316
|
+
"type": "TextColor | (string & {})",
|
|
2317
|
+
"required": false,
|
|
2318
|
+
"description": "Color del texto: puede ser un color del sistema de diseño o un color CSS personalizado"
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
},
|
|
2323
|
+
{
|
|
2324
|
+
"name": "CustomText",
|
|
2325
|
+
"kind": "component",
|
|
2326
|
+
"description": {
|
|
2327
|
+
"primary": "storybook",
|
|
2328
|
+
"storybook": "El componente Text permite aplicar estilos tipográficos consistentes usando los tokens de Figma. Soporta tipos (title, body, caption, code), tamaños, pesos de fuente, y valores base.",
|
|
2329
|
+
"confidence": "medium"
|
|
2330
|
+
},
|
|
2331
|
+
"examples": [
|
|
2332
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return <Text>Este es un texto básico</Text>\n }",
|
|
2333
|
+
"import { Text } from '@/modules/Text';\n\n const copy = 'Texto largo repetido o cargado desde CMS…';\n\n export default function Example() {\n return (\n <div style={{ width: 300, maxWidth: '100%' }} className=\"ui-space-y-4 ui-p-3\">\n <Text type=\"title\" size=\"h5\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"md\" textColor=\"primary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\" textColor=\"secondary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"caption\" size=\"xs\" textColor=\"tertiary\" as=\"p\">\n {copy}\n </Text>\n <Text type=\"code\" size=\"md\" as=\"p\" className=\"ui-break-words\">\n const linea = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n </Text>\n </div>\n );\n }",
|
|
2334
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"body\" size=\"xs\" weight=\"regular\">Body XS Regular</Text>\n <Text type=\"body\" size=\"sm\" weight=\"medium\">Body SM Medium</Text>\n <Text type=\"body\" size=\"md\" weight=\"semibold\">Body MD Semibold</Text>\n <Text type=\"body\" size=\"lg\" weight=\"bold\">Body LG Bold</Text>\n </>\n )\n }",
|
|
2335
|
+
"<Text type=\"title\" size=\"h1\">Heading H1</Text>\n <Text type=\"title\" size=\"h2\">Heading H2</Text>\n <Text type=\"title\" size=\"h3\">Heading H3</Text>",
|
|
2336
|
+
"import { Text } from '@/modules/Text';\n\n export default function Example() {\n return (\n <>\n <Text type=\"caption\" size=\"xs\">Caption XS</Text>\n <Text type=\"caption\" size=\"md\">Caption MD</Text>\n </>\n )\n }"
|
|
2337
|
+
],
|
|
2338
|
+
"props": {
|
|
2339
|
+
"groups": {},
|
|
2340
|
+
"deprecatedRoot": [
|
|
2341
|
+
{
|
|
2342
|
+
"name": "textColor",
|
|
2343
|
+
"type": "TextColor"
|
|
2344
|
+
}
|
|
2345
|
+
],
|
|
2346
|
+
"flat": {
|
|
2347
|
+
"size": {
|
|
2348
|
+
"name": "size",
|
|
2349
|
+
"type": "BaseSize",
|
|
2350
|
+
"required": true,
|
|
2351
|
+
"description": "Tamaño base del texto: 2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl"
|
|
2352
|
+
},
|
|
2353
|
+
"weight": {
|
|
2354
|
+
"name": "weight",
|
|
2355
|
+
"type": "TextWeight",
|
|
2356
|
+
"required": false,
|
|
2357
|
+
"description": "Peso de la fuente"
|
|
2358
|
+
},
|
|
2359
|
+
"children": {
|
|
2360
|
+
"name": "children",
|
|
2361
|
+
"type": "React.ReactNode",
|
|
2362
|
+
"required": true,
|
|
2363
|
+
"description": "Contenido del texto"
|
|
2364
|
+
},
|
|
2365
|
+
"className": {
|
|
2366
|
+
"name": "className",
|
|
2367
|
+
"type": "string",
|
|
2368
|
+
"required": false,
|
|
2369
|
+
"description": "Clase CSS adicional"
|
|
2370
|
+
},
|
|
2371
|
+
"as": {
|
|
2372
|
+
"name": "as",
|
|
2373
|
+
"type": "keyof JSX.IntrinsicElements",
|
|
2374
|
+
"required": false,
|
|
2375
|
+
"description": "Elemento HTML a renderizar (por defecto: span)"
|
|
2376
|
+
},
|
|
2377
|
+
"color": {
|
|
2378
|
+
"name": "color",
|
|
2379
|
+
"type": "TextColor | (string & {})",
|
|
2380
|
+
"required": false,
|
|
2381
|
+
"description": "Color del texto: puede ser un color del sistema de diseño o un color CSS personalizado"
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
]
|
|
2387
|
+
},
|
|
2388
|
+
{
|
|
2389
|
+
"id": "TextListWithData",
|
|
2390
|
+
"path": "src/modules/TextListWithData",
|
|
2391
|
+
"legacy": false,
|
|
2392
|
+
"compositionType": 1,
|
|
2393
|
+
"exports": [
|
|
2394
|
+
{
|
|
2395
|
+
"name": "TextListWithData",
|
|
2396
|
+
"kind": "component",
|
|
2397
|
+
"description": {
|
|
2398
|
+
"primary": "storybook",
|
|
2399
|
+
"storybook": "El componente TextListWithData muestra un texto con un indicador circular de color y un valor asociado. Útil para mostrar etiquetas con datos numéricos o textuales.",
|
|
2400
|
+
"jsdoc": "TextListWithData - Texto con indicador de color y valor\nMuestra un texto con un indicador circular de color y un valor asociado.\nÚtil para mostrar etiquetas con datos numéricos o textuales.",
|
|
2401
|
+
"confidence": "high"
|
|
2402
|
+
},
|
|
2403
|
+
"examples": []
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
"name": "TextListIndicator",
|
|
2407
|
+
"kind": "component",
|
|
2408
|
+
"description": {
|
|
2409
|
+
"primary": "storybook",
|
|
2410
|
+
"storybook": "El componente TextListWithData muestra un texto con un indicador circular de color y un valor asociado. Útil para mostrar etiquetas con datos numéricos o textuales.",
|
|
2411
|
+
"jsdoc": "Color del indicador (valor CSS) */\n color: string;\n /** Tamaño del indicador en píxeles */\n size: number;\n /** Clase CSS adicional */\n className?: string;\n}\n\n/**\nIndicador circular de color\nÁtomo que representa un punto de color para identificar categorías",
|
|
2412
|
+
"confidence": "high"
|
|
2413
|
+
},
|
|
2414
|
+
"examples": []
|
|
2415
|
+
}
|
|
2416
|
+
]
|
|
2417
|
+
},
|
|
2418
|
+
{
|
|
2419
|
+
"id": "Textarea",
|
|
2420
|
+
"path": "src/modules/Textarea",
|
|
2421
|
+
"legacy": false,
|
|
2422
|
+
"compositionType": 1,
|
|
2423
|
+
"exports": [
|
|
2424
|
+
{
|
|
2425
|
+
"name": "Textarea",
|
|
2426
|
+
"kind": "component",
|
|
2427
|
+
"description": {
|
|
2428
|
+
"primary": "jsdoc",
|
|
2429
|
+
"jsdoc": "Textarea - Componente de área de texto versátil y configurable\nComponente de textarea que soporta labels, mensajes de error, slots personalizados,\ncontador de caracteres, límite de longitud y estados controlados/no controlados.",
|
|
2430
|
+
"confidence": "medium"
|
|
2431
|
+
},
|
|
2432
|
+
"examples": [
|
|
2433
|
+
"import { Textarea } from '@/modules/Textarea';\n\n export default function Example() {\n const [value, setValue] = useState('');\n return <Textarea value={value} onChange={setValue} />;\n }",
|
|
2434
|
+
"<Textarea \n value={value} \n onChange={setValue} \n placeholder=\"Escribe tu mensaje aquí...\"\n />",
|
|
2435
|
+
"<Textarea \n value={value} \n onChange={setValue} \n leftSlot={faAlignCenter}\n rightSlot={faList}\n />",
|
|
2436
|
+
"<Textarea \n value={value} \n onChange={setValue} \n leftSlot={faSearch}\n />",
|
|
2437
|
+
"<Textarea \n value={value} \n onChange={setValue} \n rightSlot={faPaperPlane}\n />"
|
|
2438
|
+
]
|
|
2439
|
+
}
|
|
2440
|
+
]
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
"id": "Title",
|
|
2444
|
+
"path": "src/modules/Title",
|
|
2445
|
+
"legacy": false,
|
|
2446
|
+
"compositionType": 1,
|
|
2447
|
+
"exports": [
|
|
2448
|
+
{
|
|
2449
|
+
"name": "Title",
|
|
2450
|
+
"kind": "component",
|
|
2451
|
+
"description": {
|
|
2452
|
+
"primary": "storybook",
|
|
2453
|
+
"storybook": "El componente Title proporciona un título con soporte para:\n- Título de texto personalizable (mediante prop \\",
|
|
2454
|
+
"jsdoc": "Title - Componente de título con soporte para iconos\nComponente que renderiza un título (h1) con opción de mostrar un icono.\nSoporta iconos duotone y centrado del contenido.",
|
|
2455
|
+
"confidence": "high"
|
|
2456
|
+
},
|
|
2457
|
+
"examples": [
|
|
2458
|
+
"import { Title } from '@/modules/Title';\n\nexport default function Example() {\n return (\n <>\n {/* Usando prop title */}\n <Title title=\"Mi Título Principal\" />\n \n {/* Usando children */}\n <Title>Mi Título Principal</Title>\n </>\n );\n}",
|
|
2459
|
+
"import { Title } from '@/modules/Title';\nimport { faFolder, faCheckCircle } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function Example() {\n return (\n <>\n {/* Texto simple */}\n <Title>Mi Título con Children</Title>\n \n {/* Con formato */}\n <Title>\n Título con <span className=\"ui-text-brand\">texto destacado</span>\n </Title>\n \n {/* Con icono */}\n <Title icon={faFolder}>\n Carpeta de Documentos\n </Title>\n \n {/* Centrado */}\n <Title center icon={faCheckCircle}>\n Operación Completada\n </Title>\n \n {/* Múltiples elementos */}\n <Title>\n Título con <span className=\"ui-text-success\">éxito</span> y <span className=\"ui-text-danger\">error</span>\n </Title>\n </>\n );\n}",
|
|
2460
|
+
"import { Title } from '@/modules/Title';\nimport { faFolder, faCalendar } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function Example() {\n return (\n <>\n <Title title=\"Carpetas\" icon={faFolder} />\n <Title title=\"Calendario\" icon={faCalendar} />\n </>\n );\n}",
|
|
2461
|
+
"import { Title } from '@/modules/Title';\nimport { faCheckCircle, faExclamationTriangle } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function Example() {\n return (\n <>\n <Title\n title=\"Operación Exitosa\"\n icon={faCheckCircle}\n iconDuotonePrimary=\"success\"\n iconDuotoneSecondary=\"green\"\n iconDuotoneOpacityPrimary={1}\n iconDuotoneOpacitySecondary={0.4}\n />\n <Title\n title=\"Advertencia Importante\"\n icon={faExclamationTriangle}\n iconDuotonePrimary=\"warning\"\n iconDuotoneSecondary=\"yellow\"\n iconDuotoneOpacityPrimary={1}\n iconDuotoneOpacitySecondary={0.4}\n />\n </>\n );\n}",
|
|
2462
|
+
"import { Title } from '@/modules/Title';\nimport { faFolder, faCalendar } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function Example() {\n return (\n <>\n <Title\n title=\"Carpetas Organizadas\"\n icon={faFolder}\n iconDuotonePrimary=\"azure\"\n iconDuotoneSecondary=\"blue\"\n iconDuotoneOpacityPrimary={1}\n iconDuotoneOpacitySecondary={0.4}\n />\n <Title\n title=\"Eventos del Mes\"\n icon={faCalendar}\n iconDuotonePrimary=\"violet\"\n iconDuotoneSecondary=\"magenta\"\n iconDuotoneOpacityPrimary={1}\n iconDuotoneOpacitySecondary={0.4}\n />\n </>\n );\n}"
|
|
2463
|
+
]
|
|
2464
|
+
}
|
|
2465
|
+
]
|
|
2466
|
+
},
|
|
2467
|
+
{
|
|
2468
|
+
"id": "Toast",
|
|
2469
|
+
"path": "src/modules/Toast",
|
|
2470
|
+
"legacy": false,
|
|
2471
|
+
"compositionType": 1,
|
|
2472
|
+
"exports": [
|
|
2473
|
+
{
|
|
2474
|
+
"name": "Toaster",
|
|
2475
|
+
"kind": "component",
|
|
2476
|
+
"description": {
|
|
2477
|
+
"primary": "readme",
|
|
2478
|
+
"readme": "# Toast Component\n\nComponente de notificaciones toast modular y configurable con múltiples variantes y posiciones.\n\n## Estructura\n\n```\nToast/\n├── config/\n│ ├── index.ts\n│ └── toast.config.ts # Configuración del toast\n├── hooks/\n│ ├── index.ts\n│ ├── useToast.ts # Hook principal para manejar toasts\n│ ├── useToastService.ts # Servicio de toast\n│ └── useToastStyles.ts # Hook para estilos y utilidades\n├── components/\n│ ├── atoms/\n│ │ ├── ToastHeader.tsx # Encabezado del toast\n│ │ └── ToastFooter.tsx # Pie del toast\n│ └── molecules/\n│ ├── ToastItem.tsx # Item individual del toast\n│ └── ToastPositions.tsx # Contenedor de posiciones\n├── stories/\n│ └── toast.stories.tsx # Storybook stories\n├── index.tsx # Componente principal\n└── README.md # Este archivo\n```\n\n## Uso\n\n### Básico\n\n```tsx\nimport { toast, Toaster } from '@/modules/Toast';\n\n// Mostrar un toast\ntoast.success('Operación exitosa');\ntoast.error('Algo salió mal');\ntoast.info('Información importante');\ntoast.warning('Advertencia');\n\n// En tu componente\nfunction App() {\n return (\n <div>\n <Toaster />\n {/* resto de tu app */}\n </div>\n );\n}\n```\n\n### Con título\n\n```tsx\n// Toast con título\ntoast.success('Usuario creado correctamente', {\n title: 'Éxito',\n});\n\ntoast.error('No se pudo conectar al servidor', {\n title: 'Error de conexión',\n});\n\ntoast.info('Tu sesión expirará en 5 minutos', {\n title: 'Sesión',\n});\n\ntoast.warning('Los cambios no se han guardado', {\n title: 'Advertencia',\n});\n```\n\n### Sin botón de cerrar\n\n```tsx\n// Toast sin botón de cerrar (se cerrará automáticamente)\ntoast.success('Mensaje temporal', {\n showCloseButton: false,\n});\n\n// Toast con título pero sin botón de cerrar\ntoast.info('Procesando...', {\n title: 'Carga',\n showCloseButton: false,\n duration: 3000,\n});\n```\n\n### Variantes de estilo\n\n```tsx\n// Variante contained (por defecto)\ntoast.success('",
|
|
2479
|
+
"confidence": "low"
|
|
2480
|
+
},
|
|
2481
|
+
"examples": [
|
|
2482
|
+
"// ✅ Nueva forma (recomendada)\n import { notify, Messaging, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Messaging />\n <Button onClick={() => notify.success(\"Hello, world!\")}>Success</Button>\n </div>\n )\n\n // ✅ Forma legacy (sigue funcionando)\n import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Toaster />\n <Button onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n </div>\n )",
|
|
2483
|
+
"import { notify } from '@imj_media'; // o import { toast } para compatibilidad\n\n notify.success(\"Hello, world!\")\n notify.error(\"Hello, world!\")\n notify.info(\"Hello, world!\")\n notify.warning(\"Hello, world!\")\n \n // ✨ Nuevos métodos disponibles con notify\n notify.message({ stackGroup: 'secondary', title: 'Mensaje neutro' })\n notify.message({ title: 'Mensaje de marca' })\n\n notify.success({\n message: \"Hello, world!\",\n title: \"Success\",\n position: 'top-center',\n variant: 'outlined'\n })\n\n notify.success(\"Hello, world!\", {\n title: \"Success\",\n position: 'top-center',\n variant: 'outlined'\n })",
|
|
2484
|
+
"import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => {\n\n toast.configure({ \n duration: 5000,\n maxMessages: 5,\n position: 'bottom-right',\n variant: 'contained',\n primaryButtonText: 'Aceptar',\n secondaryButtonText: 'Cancelar'\n }) \n\n return (\n <div>\n <Toaster />\n <Button variant=\"contained\" color=\"success\" onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n </div>\n )\n }",
|
|
2485
|
+
"import { toast, Toaster } from '@/modules/Toast';\n import { Button } from '@/modules/Button';\n\n import { faCheck, faExclamationTriangle, faInfoCircle } from '@fortawesome/pro-regular-svg-icons';\n export default function Example() {\n return (\n <>\n <Toaster />\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"danger\" onClick={() => toast.error(\"Hello, world!\", { position: 'top-left' })}>Error</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.info(\"Hello, world!\")}>Info</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.warning(\"Hello, world!\")}>Warning</Button>\n </>\n )\n }",
|
|
2486
|
+
"// Tamaño pequeño (por defecto)\n toast.success({\n message: \"Toast con tamaño pequeño\",\n title: \"Tamaño SM\",\n size: 'sm'\n })\n\n // Tamaño mediano\n toast.info({\n message: \"Toast con tamaño mediano\", \n title: \"Tamaño MD\",\n size: 'md'\n })"
|
|
2487
|
+
]
|
|
2488
|
+
},
|
|
2489
|
+
{
|
|
2490
|
+
"name": "Messaging",
|
|
2491
|
+
"kind": "component",
|
|
2492
|
+
"description": {
|
|
2493
|
+
"primary": "readme",
|
|
2494
|
+
"readme": "# Toast Component\n\nComponente de notificaciones toast modular y configurable con múltiples variantes y posiciones.\n\n## Estructura\n\n```\nToast/\n├── config/\n│ ├── index.ts\n│ └── toast.config.ts # Configuración del toast\n├── hooks/\n│ ├── index.ts\n│ ├── useToast.ts # Hook principal para manejar toasts\n│ ├── useToastService.ts # Servicio de toast\n│ └── useToastStyles.ts # Hook para estilos y utilidades\n├── components/\n│ ├── atoms/\n│ │ ├── ToastHeader.tsx # Encabezado del toast\n│ │ └── ToastFooter.tsx # Pie del toast\n│ └── molecules/\n│ ├── ToastItem.tsx # Item individual del toast\n│ └── ToastPositions.tsx # Contenedor de posiciones\n├── stories/\n│ └── toast.stories.tsx # Storybook stories\n├── index.tsx # Componente principal\n└── README.md # Este archivo\n```\n\n## Uso\n\n### Básico\n\n```tsx\nimport { toast, Toaster } from '@/modules/Toast';\n\n// Mostrar un toast\ntoast.success('Operación exitosa');\ntoast.error('Algo salió mal');\ntoast.info('Información importante');\ntoast.warning('Advertencia');\n\n// En tu componente\nfunction App() {\n return (\n <div>\n <Toaster />\n {/* resto de tu app */}\n </div>\n );\n}\n```\n\n### Con título\n\n```tsx\n// Toast con título\ntoast.success('Usuario creado correctamente', {\n title: 'Éxito',\n});\n\ntoast.error('No se pudo conectar al servidor', {\n title: 'Error de conexión',\n});\n\ntoast.info('Tu sesión expirará en 5 minutos', {\n title: 'Sesión',\n});\n\ntoast.warning('Los cambios no se han guardado', {\n title: 'Advertencia',\n});\n```\n\n### Sin botón de cerrar\n\n```tsx\n// Toast sin botón de cerrar (se cerrará automáticamente)\ntoast.success('Mensaje temporal', {\n showCloseButton: false,\n});\n\n// Toast con título pero sin botón de cerrar\ntoast.info('Procesando...', {\n title: 'Carga',\n showCloseButton: false,\n duration: 3000,\n});\n```\n\n### Variantes de estilo\n\n```tsx\n// Variante contained (por defecto)\ntoast.success('",
|
|
2495
|
+
"confidence": "low"
|
|
2496
|
+
},
|
|
2497
|
+
"examples": [
|
|
2498
|
+
"// ✅ Nueva forma (recomendada)\n import { notify, Messaging, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Messaging />\n <Button onClick={() => notify.success(\"Hello, world!\")}>Success</Button>\n </div>\n )\n\n // ✅ Forma legacy (sigue funcionando)\n import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => (\n <div>\n <Toaster />\n <Button onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n </div>\n )",
|
|
2499
|
+
"import { notify } from '@imj_media'; // o import { toast } para compatibilidad\n\n notify.success(\"Hello, world!\")\n notify.error(\"Hello, world!\")\n notify.info(\"Hello, world!\")\n notify.warning(\"Hello, world!\")\n \n // ✨ Nuevos métodos disponibles con notify\n notify.message({ stackGroup: 'secondary', title: 'Mensaje neutro' })\n notify.message({ title: 'Mensaje de marca' })\n\n notify.success({\n message: \"Hello, world!\",\n title: \"Success\",\n position: 'top-center',\n variant: 'outlined'\n })\n\n notify.success(\"Hello, world!\", {\n title: \"Success\",\n position: 'top-center',\n variant: 'outlined'\n })",
|
|
2500
|
+
"import { toast, Toaster, Button } from '@imj_media';\n\n export const App = () => {\n\n toast.configure({ \n duration: 5000,\n maxMessages: 5,\n position: 'bottom-right',\n variant: 'contained',\n primaryButtonText: 'Aceptar',\n secondaryButtonText: 'Cancelar'\n }) \n\n return (\n <div>\n <Toaster />\n <Button variant=\"contained\" color=\"success\" onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n </div>\n )\n }",
|
|
2501
|
+
"import { toast, Toaster } from '@/modules/Toast';\n import { Button } from '@/modules/Button';\n\n import { faCheck, faExclamationTriangle, faInfoCircle } from '@fortawesome/pro-regular-svg-icons';\n export default function Example() {\n return (\n <>\n <Toaster />\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.success(\"Hello, world!\")}>Success</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"danger\" onClick={() => toast.error(\"Hello, world!\", { position: 'top-left' })}>Error</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.info(\"Hello, world!\")}>Info</Button>\n <Button size=\"sm\" theme=\"solid\" color=\"primary\" onClick={() => toast.warning(\"Hello, world!\")}>Warning</Button>\n </>\n )\n }",
|
|
2502
|
+
"// Tamaño pequeño (por defecto)\n toast.success({\n message: \"Toast con tamaño pequeño\",\n title: \"Tamaño SM\",\n size: 'sm'\n })\n\n // Tamaño mediano\n toast.info({\n message: \"Toast con tamaño mediano\", \n title: \"Tamaño MD\",\n size: 'md'\n })"
|
|
2503
|
+
]
|
|
2504
|
+
}
|
|
2505
|
+
]
|
|
2506
|
+
},
|
|
2507
|
+
{
|
|
2508
|
+
"id": "Toggle",
|
|
2509
|
+
"path": "src/modules/Toggle",
|
|
2510
|
+
"legacy": false,
|
|
2511
|
+
"compositionType": 1,
|
|
2512
|
+
"exports": [
|
|
2513
|
+
{
|
|
2514
|
+
"name": "TOGGLE_DESIGN_TOKENS",
|
|
2515
|
+
"kind": "component",
|
|
2516
|
+
"description": {
|
|
2517
|
+
"primary": "jsdoc",
|
|
2518
|
+
"jsdoc": "Tokens semánticos del Toggle según diseño de Figma\nEl componente usa clases semánticas de Tailwind configuradas con variables CSS de Figma:\nCOLORES (tokens semánticos):\n- Activo: ui-bg-fill-brand → var(--ui-color-bg-fill-brand-default) = #3658c1\n- Inactivo: ui-bg-fill-brand-disabled → var(--ui-color-bg-fill-brand-disabled) = #b8c5ee\n- Disabled: ui-bg-fill-hover → var(--ui-color-bg-fill-hover) = #f0f1f2\n- Border: ui-border-DEFAULT → var(--ui-color-border-default) = #c6c8cc\n- Thumb: ui-bg-fill = #ffffff\n- Text: ui-text-primary → var(--ui-color-text-primary) = #313336\nDIMENSIONES (clases de Tailwind con Positive Space):\n- Container width: ui-w-32 → var(--ui-Positive-space_32) = 32px\n- Container height: ui-h-20 → var(--ui-Positive-space_20) = 20px\n- Thumb: ui-w-16 ui-h-16 → var(--ui-Positive-s",
|
|
2519
|
+
"readme": "# Toggle Component\n\nComponente Toggle (interruptor) altamente configurable y accesible para React, construido fielmente siguiendo el diseño de Figma.\n\n## Características\n\n- ✅ **Diseño fiel a Figma** (32x20px, colores exactos)\n- ✅ Soporta modo controlado y no controlado\n- ✅ Label opcional con icono y posición configurable\n- ✅ Variante con stroke (borde)\n- ✅ Estados: activo, inactivo, disabled\n- ✅ Animaciones suaves\n- ✅ Totalmente accesible (ARIA)\n- ✅ Clases semánticas con prefijo `ui-`\n- ✅ TypeScript completo\n- ✅ Hook personalizado reutilizable\n\n## Especificaciones de Diseño (Figma)\n\n### Dimensiones (usando clases de Tailwind con Positive Space)\n\n- **Container width**: `ui-w-32` → `var(--ui-Positive-space_32)` = 32px\n- **Container height**: `ui-h-20` → `var(--ui-Positive-space_20)` = 20px\n- **Thumb**: `ui-w-16 ui-h-16` → `var(--ui-Positive-space_16)` = 16px\n- **Border radius**: `ui-rounded-2xl` = 16px\n- **Padding**: `ui-px-2` → `var(--ui-Positive-space_2)` = 2px\n- **Gap**: `ui-gap-8` → `var(--ui-Positive-space_8)` = 8px\n\n### Colores (usando tokens semánticos)\n\n- **Activo**: `ui-bg-fill-brand` → `var(--ui-color-bg-fill-brand-default)` = `#3658c1`\n- **Inactivo**: `ui-bg-fill-brand-disabled` → `var(--ui-color-bg-fill-brand-disabled)` = `#b8c5ee`\n- **Disabled**: `ui-bg-fill-hover` → `var(--ui-color-bg-fill-hover)` = `#f0f1f2`\n- **Border**: `ui-border-DEFAULT` → `var(--ui-color-border-default)` = `#c6c8cc`\n- **Thumb**: `ui-bg-fill` = `#ffffff`\n- **Text**: `ui-text-primary` → `var(--ui-color-text-primary)` = `#313336`\n\n### Tipografía (según Type/Body/SM/Bold de Figma)\n\n- **Weight**: `ui-font-body-sm-bold` (700)\n- **Size**: `ui-text-body-sm-bold` (14px)\n- **Line Height**: `20.5px`\n- **Tracking**: `0.5px`\n\n## Uso Básico\n\n```tsx\nimport { Toggle } from '@/modules/Toggle'\n\n// Sin label\n<Toggle ariaLabel=\"Activar función\" />\n\n// Con label\n<Toggle label=\"Notificaciones\" />\n\n// Controlado\nconst [enabled, setEnabled] = useState(false)\n<Toggle\n checked={enabled}\n onChange={setEnab",
|
|
2520
|
+
"confidence": "medium"
|
|
2521
|
+
},
|
|
2522
|
+
"examples": []
|
|
2523
|
+
}
|
|
2524
|
+
]
|
|
2525
|
+
},
|
|
2526
|
+
{
|
|
2527
|
+
"id": "Toolbar",
|
|
2528
|
+
"path": "src/modules/Toolbar",
|
|
2529
|
+
"legacy": false,
|
|
2530
|
+
"compositionType": 1,
|
|
2531
|
+
"exports": [
|
|
2532
|
+
{
|
|
2533
|
+
"name": "Toolbar",
|
|
2534
|
+
"kind": "component",
|
|
2535
|
+
"description": {
|
|
2536
|
+
"primary": "storybook",
|
|
2537
|
+
"storybook": "## Toolbar - Barra de herramientas flexible\n\nUn componente flexible que muestra botones en una barra flotante. Cada botón puede tener sus propios addons (inputs/date pickers) asociados.\n\n### Características principales:\n- **Vista de botones**: Siempre se muestra primero\n- **Addons por botón**: Cada botón puede tener sus propios addons\n- **Navegación**: Al hacer click en un botón con addons, se muestra la vista de addons\n- **Botón de volver**: Permite regresar a la vista de botones\n- **Botón de cerrar**: Oculta el toolbar completamente\n- **Contador**: Muestra",
|
|
2538
|
+
"jsdoc": "Toolbar - Barra de herramientas flexible con botones y addons\nSegún diseño de Figma:\n- Fondo: bg-fill-brand (azul)\n- Border radius: radius-surface-modal (16px)\n- Padding: 16px horizontal, 8px vertical\n- Gap: 16px entre elementos\n- Texto blanco para el contador\n- Divisor vertical entre secciones\nFuncionamiento:\n1. Siempre se muestra primero la vista de botones\n2. Cada botón puede tener sus propios addons asociados\n3. Al hacer click en un botón:\n - Se ejecuta onClick (siempre)\n - Si tiene addons, se muestra la vista de addons de ese botón\n4. En la vista de addons se muestra (por defecto):\n - Botón de volver (opcional con `showBackButton={false}`)\n - Texto con contador \"(count) text\"\n - Los addons del botón seleccionado\n - Botón de cerrar (si `onClose` está definido y `showCloseBu",
|
|
2539
|
+
"confidence": "high"
|
|
2540
|
+
},
|
|
2541
|
+
"examples": []
|
|
2542
|
+
}
|
|
2543
|
+
]
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
"id": "Tooltip",
|
|
2547
|
+
"path": "src/modules/Tooltip",
|
|
2548
|
+
"legacy": false,
|
|
2549
|
+
"compositionType": 1,
|
|
2550
|
+
"exports": [
|
|
2551
|
+
{
|
|
2552
|
+
"name": "Tooltip",
|
|
2553
|
+
"kind": "component",
|
|
2554
|
+
"description": {
|
|
2555
|
+
"primary": "storybook",
|
|
2556
|
+
"storybook": "El componente Tooltip permite mostrar información contextual cuando el usuario hace hover sobre un elemento. Soporta múltiples posiciones, colores y configuraciones.",
|
|
2557
|
+
"jsdoc": "TooltipComponent - Componente interno de tooltip con posicionamiento avanzado\nComponente que renderiza el tooltip con posicionamiento dinámico, flecha ajustable\ny soporte para múltiples posiciones y alineaciones.\nEl copy usa {@link Body} (equivalente a `Text` con `type=\"body\"`) para tokens de\ntipografía y color en tema claro/oscuro; no se importa `Text` aquí para evitar\ndependencia circular con el truncado que envuelve `Text`.\n@internal\n/\nconst TooltipComponent = ({\n children,\n label,\n position = 'top',\n alignment = 'center',\n id = `tooltip-${Math.random().toString(36).substring(2, 9)}`,\n delay = 0,\n disabled = false,\n className = '',\n fullWidth = false,\n style,\n arrowClassName,\n absolute = false,\n preserveLayout = false,\n ...props\n}: TooltipProps) => {\n const {\n isVisibl",
|
|
2558
|
+
"confidence": "high"
|
|
2559
|
+
},
|
|
2560
|
+
"examples": [
|
|
2561
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\n export default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n }",
|
|
2562
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\nexport default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n}",
|
|
2563
|
+
"<Tooltip label=\"Este tooltip aparece después de 500ms\" delay={500}>\n <InnerButton color=\"secondary\">Hover me (delay 500ms)</InnerButton>\n </Tooltip>",
|
|
2564
|
+
"<Tooltip label=\"No deberías ver este tooltip\" disabled={true}>\n <InnerButton color=\"neutral\">Este tooltip está deshabilitado</InnerButton>\n </Tooltip>",
|
|
2565
|
+
"<Tooltip label=\"Tooltip arriba\" position=\"top\">\n <InnerButton color=\"primary\">Top</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip abajo\" position=\"bottom\">\n <InnerButton color=\"secondary\">Bottom</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip izquierda\" position=\"left\">\n <InnerButton color=\"destructive\">Left</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip derecha\" position=\"right\">\n <InnerButton color=\"tertiary\">Right</InnerButton>\n </Tooltip>"
|
|
2566
|
+
]
|
|
2567
|
+
},
|
|
2568
|
+
{
|
|
2569
|
+
"name": "InlineTooltip",
|
|
2570
|
+
"kind": "component",
|
|
2571
|
+
"description": {
|
|
2572
|
+
"primary": "storybook",
|
|
2573
|
+
"storybook": "El componente Tooltip permite mostrar información contextual cuando el usuario hace hover sobre un elemento. Soporta múltiples posiciones, colores y configuraciones.",
|
|
2574
|
+
"jsdoc": "Contenido del tooltip */\n label: React.ReactNode;\n /** Si el tooltip está visible */\n isVisible: boolean;\n /** Posición del tooltip */\n position?: InlineTooltipPosition;\n /** Clase adicional para el tooltip */\n className?: string;\n}\n\n/**\nInlineTooltip - Tooltip CSS puro para usar dentro de elementos flex\nEste componente es útil cuando el Tooltip normal interfiere con layouts flex.\nSe posiciona absolutamente dentro del elemento padre que debe tener `position: relative`.",
|
|
2575
|
+
"confidence": "high"
|
|
2576
|
+
},
|
|
2577
|
+
"examples": [
|
|
2578
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\n export default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n }",
|
|
2579
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\nexport default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n}",
|
|
2580
|
+
"<Tooltip label=\"Este tooltip aparece después de 500ms\" delay={500}>\n <InnerButton color=\"secondary\">Hover me (delay 500ms)</InnerButton>\n </Tooltip>",
|
|
2581
|
+
"<Tooltip label=\"No deberías ver este tooltip\" disabled={true}>\n <InnerButton color=\"neutral\">Este tooltip está deshabilitado</InnerButton>\n </Tooltip>",
|
|
2582
|
+
"<Tooltip label=\"Tooltip arriba\" position=\"top\">\n <InnerButton color=\"primary\">Top</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip abajo\" position=\"bottom\">\n <InnerButton color=\"secondary\">Bottom</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip izquierda\" position=\"left\">\n <InnerButton color=\"destructive\">Left</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip derecha\" position=\"right\">\n <InnerButton color=\"tertiary\">Right</InnerButton>\n </Tooltip>"
|
|
2583
|
+
]
|
|
2584
|
+
},
|
|
2585
|
+
{
|
|
2586
|
+
"name": "TruncatedWithTooltip",
|
|
2587
|
+
"kind": "component",
|
|
2588
|
+
"description": {
|
|
2589
|
+
"primary": "storybook",
|
|
2590
|
+
"storybook": "El componente Tooltip permite mostrar información contextual cuando el usuario hace hover sobre un elemento. Soporta múltiples posiciones, colores y configuraciones.",
|
|
2591
|
+
"jsdoc": "Con `text-overflow: ellipsis`, en Chromium/WebKit suele cumplirse `scrollWidth === clientWidth`\naunque el texto esté recortado; el tooltip quedaría deshabilitado si solo usáramos esa comparación.\n/\nfunction isTextTruncatedInElement(el: HTMLElement): boolean {\n if (el.scrollWidth > el.clientWidth) {\n return true;\n }\n const text = el.textContent ?? '';\n if (!text.trim()) {\n return false;\n }\n const containerWidth = el.getBoundingClientRect().width;\n if (containerWidth < 1) {\n return false;\n }\n const style = window.getComputedStyle(el);\n const clone = document.createElement('span');\n clone.setAttribute('aria-hidden', 'true');\n clone.style.position = 'absolute';\n clone.style.visibility = 'hidden';\n clone.style.whiteSpace = 'nowrap';\n clone.style.top = '0';\n clone.style.",
|
|
2592
|
+
"confidence": "high"
|
|
2593
|
+
},
|
|
2594
|
+
"examples": [
|
|
2595
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\n export default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n }",
|
|
2596
|
+
"import { Tooltip } from '@/modules/Tooltip';\n\nexport default function Example() {\n return (\n <Tooltip label=\"Este es un tooltip básico\">\n <InnerButton color=\"primary\">Hover me</InnerButton>\n </Tooltip>\n )\n}",
|
|
2597
|
+
"<Tooltip label=\"Este tooltip aparece después de 500ms\" delay={500}>\n <InnerButton color=\"secondary\">Hover me (delay 500ms)</InnerButton>\n </Tooltip>",
|
|
2598
|
+
"<Tooltip label=\"No deberías ver este tooltip\" disabled={true}>\n <InnerButton color=\"neutral\">Este tooltip está deshabilitado</InnerButton>\n </Tooltip>",
|
|
2599
|
+
"<Tooltip label=\"Tooltip arriba\" position=\"top\">\n <InnerButton color=\"primary\">Top</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip abajo\" position=\"bottom\">\n <InnerButton color=\"secondary\">Bottom</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip izquierda\" position=\"left\">\n <InnerButton color=\"destructive\">Left</InnerButton>\n </Tooltip>\n <Tooltip label=\"Tooltip derecha\" position=\"right\">\n <InnerButton color=\"tertiary\">Right</InnerButton>\n </Tooltip>"
|
|
2600
|
+
]
|
|
2601
|
+
}
|
|
2602
|
+
]
|
|
2603
|
+
},
|
|
2604
|
+
{
|
|
2605
|
+
"id": "Visual",
|
|
2606
|
+
"path": "src/modules/Visual",
|
|
2607
|
+
"legacy": false,
|
|
2608
|
+
"compositionType": 1,
|
|
2609
|
+
"exports": [
|
|
2610
|
+
{
|
|
2611
|
+
"name": "Visual",
|
|
2612
|
+
"kind": "component",
|
|
2613
|
+
"description": {
|
|
2614
|
+
"primary": "jsdoc",
|
|
2615
|
+
"jsdoc": "Visual - Componente visual versátil (icono, imagen o avatar)\nComponente que renderiza diferentes tipos de contenido visual según el slot proporcionado:\niconos, imágenes (URL o base64), avatares o contenido personalizado.\nSoporta tooltips, estados de hover y fallbacks.",
|
|
2616
|
+
"confidence": "medium"
|
|
2617
|
+
},
|
|
2618
|
+
"examples": [
|
|
2619
|
+
"import { Visual } from '@/modules/Visual';\n\n export default function Example() {\n return <Visual tooltip=\"Editor\" slot=\"https://pc.net/img/terms/avatar.svg\" size='6xl' defaultSizeIcon={false} />\n }",
|
|
2620
|
+
"import { Visual } from '@/modules/Visual';\nimport { faFolder, faCalendar, faEnvelope } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function DuotoneExample() {\n return (\n <>\n <Visual\n slot={faFolder}\n size=\"xl\"\n colorIconDuotonePrimary=\"brand\"\n colorIconDuotoneSecondary=\"azure\"\n opacityIconDuotonePrimary={1}\n opacityIconDuotoneSecondary={0.4}\n />\n <Visual\n slot={faCalendar}\n size=\"xl\"\n colorIconDuotonePrimary=\"success\"\n colorIconDuotoneSecondary=\"green\"\n opacityIconDuotonePrimary={1}\n opacityIconDuotoneSecondary={0.4}\n />\n </>\n );\n}",
|
|
2621
|
+
"import { Visual } from '@/modules/Visual';\n\n export default function Example() {\n return <Visual tooltip=\"Editor\" slot=\"https://pc.net/img/terms/avatar.svg\" size='6xl' defaultSizeIcon={false} />\n }",
|
|
2622
|
+
"import { Visual } from '@/modules/Visual';\nimport { faFolder, faCalendar, faEnvelope } from '@fortawesome/pro-duotone-svg-icons';\n\nexport default function DuotoneExample() {\n return (\n <>\n <Visual\n slot={faFolder}\n size=\"xl\"\n colorIconDuotonePrimary=\"brand\"\n colorIconDuotoneSecondary=\"azure\"\n opacityIconDuotonePrimary={1}\n opacityIconDuotoneSecondary={0.4}\n />\n <Visual\n slot={faCalendar}\n size=\"xl\"\n colorIconDuotonePrimary=\"success\"\n colorIconDuotoneSecondary=\"green\"\n opacityIconDuotonePrimary={1}\n opacityIconDuotoneSecondary={0.4}\n />\n </>\n );\n}"
|
|
2623
|
+
]
|
|
2624
|
+
}
|
|
2625
|
+
]
|
|
2626
|
+
},
|
|
2627
|
+
{
|
|
2628
|
+
"id": "Wysiwyg",
|
|
2629
|
+
"path": "src/modules/Wysiwyg",
|
|
2630
|
+
"legacy": false,
|
|
2631
|
+
"compositionType": 1,
|
|
2632
|
+
"exports": [
|
|
2633
|
+
{
|
|
2634
|
+
"name": "Wysiwyg",
|
|
2635
|
+
"kind": "component",
|
|
2636
|
+
"description": {
|
|
2637
|
+
"primary": "readme",
|
|
2638
|
+
"readme": "# Wysiwyg\n\nEditor de texto enriquecido (What You See Is What You Get) con soporte para formato de texto, listas, enlaces, emojis y adjuntos.\n\n## Características\n\n- ✏️ **Formato de texto**: Negrita, cursiva, subrayado, tachado\n- 📝 **Listas**: Ordenadas y sin orden\n- 🔗 **Enlaces**: Inserción de enlaces\n- 😊 **Emojis**: Integración completa con EmojiPicker\n- 📎 **Adjuntos**: Carga de archivos\n- 👤 **Menciones**: Sistema de menciones con @\n- 📏 **Altura personalizable**: Control de min/max height\n- 🎯 **Auto focus**: Opción de enfoque automático\n- ♿ **Accesible**: Totalmente accesible con teclado\n\n## Uso Básico\n\n```tsx\nimport { Wysiwyg } from '@/modules/Wysiwyg';\n\nfunction MiComponente() {\n const [content, setContent] = useState('');\n\n return (\n <Wysiwyg\n onChange={(html) => setContent(html)}\n onSubmit={() => console.log('Enviando:', content)}\n />\n );\n}\n```\n\n## Props\n\n### WysiwygProps\n\n| Prop | Tipo | Default | Descripción |\n| ------------------ | --------------------------- | ---------------------------- | ------------------------------------- |\n| `value` | `string` | `undefined` | Valor controlado del contenido HTML |\n| `defaultValue` | `string` | `''` | Valor por defecto del contenido HTML |\n| `onChange` | `(html: string) => void` | `undefined` | Callback cuando el contenido cambia |\n| `placeholder` | `string` | `'Escribe un mensaje nuevo'` | Placeholder del editor |\n| `disabled` | `boolean` | `false` | Deshabilitar el editor |\n| `showToolbar` | `boolean` | `true` | Mostrar toolbar de formato |\n| `allowAttachments` | `boolean` | `true` | Permitir",
|
|
2639
|
+
"confidence": "low"
|
|
2640
|
+
},
|
|
2641
|
+
"examples": [
|
|
2642
|
+
"const [content, setContent] = useState('')\n\n<Wysiwyg\n onChange={(html) => setContent(html)}\n onSubmit={() => console.log('Enviando:', content)}\n/>",
|
|
2643
|
+
"<Wysiwyg\n defaultValue=\"<p>Este es un <strong>mensaje inicial</strong> con <em>formato</em>.</p>\"\n onSubmit={() => alert('Mensaje enviado!')}\n/>",
|
|
2644
|
+
"<Wysiwyg\n defaultValue=\"<p>Contenido no editable</p>\"\n disabled={true}\n/>",
|
|
2645
|
+
"<Wysiwyg\n showToolbar={false}\n placeholder=\"Escribe un mensaje simple...\"\n onSubmit={() => alert('Enviado!')}\n/>",
|
|
2646
|
+
"// Editor pequeño\n<Wysiwyg\n minHeight={40}\n maxHeight={150}\n/>\n\n// Editor grande\n<Wysiwyg\n minHeight={150}\n maxHeight={500}\n/>"
|
|
2647
|
+
]
|
|
2648
|
+
}
|
|
2649
|
+
]
|
|
2650
|
+
},
|
|
2651
|
+
{
|
|
2652
|
+
"id": "imj-calendar-timeline",
|
|
2653
|
+
"path": "src/modules/imj-calendar-timeline",
|
|
2654
|
+
"legacy": false,
|
|
2655
|
+
"compositionType": 1,
|
|
2656
|
+
"exports": [
|
|
2657
|
+
{
|
|
2658
|
+
"name": "TimelineMarkers",
|
|
2659
|
+
"kind": "component",
|
|
2660
|
+
"description": {
|
|
2661
|
+
"primary": "storybook",
|
|
2662
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2663
|
+
"confidence": "medium"
|
|
2664
|
+
},
|
|
2665
|
+
"examples": []
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
"name": "TodayMarker",
|
|
2669
|
+
"kind": "component",
|
|
2670
|
+
"description": {
|
|
2671
|
+
"primary": "storybook",
|
|
2672
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2673
|
+
"jsdoc": "Marker that is placed based on current date. This component updates itself on\na set interval, dictated by the 'interval' prop.",
|
|
2674
|
+
"confidence": "high"
|
|
2675
|
+
},
|
|
2676
|
+
"examples": []
|
|
2677
|
+
},
|
|
2678
|
+
{
|
|
2679
|
+
"name": "CustomMarker",
|
|
2680
|
+
"kind": "component",
|
|
2681
|
+
"description": {
|
|
2682
|
+
"primary": "storybook",
|
|
2683
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2684
|
+
"jsdoc": "CustomMarker that is placed based on passed in date prop",
|
|
2685
|
+
"confidence": "high"
|
|
2686
|
+
},
|
|
2687
|
+
"examples": []
|
|
2688
|
+
},
|
|
2689
|
+
{
|
|
2690
|
+
"name": "CursorMarker",
|
|
2691
|
+
"kind": "component",
|
|
2692
|
+
"description": {
|
|
2693
|
+
"primary": "storybook",
|
|
2694
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2695
|
+
"jsdoc": "CursorMarker implementation subscribes to 'subscribeToCanvasMouseOver' on mount.\nThis subscription is passed in via MarkerCanvasConsumer, which is wired up to\nMarkerCanvasProvider in the MarkerCanvas component. When the user mouses over MarkerCanvas,\nthe callback registered in CursorMarker (this component) is passed:\n leftOffset - pixels from left edge of canvas, used to position this element\n date - the date the cursor pertains to\n isCursorOverCanvas - whether the user cursor is over the canvas. This is set to 'false'\n when the user mouseleaves the element",
|
|
2696
|
+
"confidence": "high"
|
|
2697
|
+
},
|
|
2698
|
+
"examples": []
|
|
2699
|
+
},
|
|
2700
|
+
{
|
|
2701
|
+
"name": "TimelineHeaders",
|
|
2702
|
+
"kind": "component",
|
|
2703
|
+
"description": {
|
|
2704
|
+
"primary": "storybook",
|
|
2705
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2706
|
+
"confidence": "medium"
|
|
2707
|
+
},
|
|
2708
|
+
"examples": []
|
|
2709
|
+
},
|
|
2710
|
+
{
|
|
2711
|
+
"name": "SidebarHeader",
|
|
2712
|
+
"kind": "component",
|
|
2713
|
+
"description": {
|
|
2714
|
+
"primary": "storybook",
|
|
2715
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2716
|
+
"confidence": "medium"
|
|
2717
|
+
},
|
|
2718
|
+
"examples": []
|
|
2719
|
+
},
|
|
2720
|
+
{
|
|
2721
|
+
"name": "CustomHeader",
|
|
2722
|
+
"kind": "component",
|
|
2723
|
+
"description": {
|
|
2724
|
+
"primary": "storybook",
|
|
2725
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2726
|
+
"confidence": "medium"
|
|
2727
|
+
},
|
|
2728
|
+
"examples": []
|
|
2729
|
+
},
|
|
2730
|
+
{
|
|
2731
|
+
"name": "DateHeader",
|
|
2732
|
+
"kind": "component",
|
|
2733
|
+
"description": {
|
|
2734
|
+
"primary": "storybook",
|
|
2735
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2736
|
+
"confidence": "medium"
|
|
2737
|
+
},
|
|
2738
|
+
"examples": []
|
|
2739
|
+
},
|
|
2740
|
+
{
|
|
2741
|
+
"name": "GroupRow",
|
|
2742
|
+
"kind": "component",
|
|
2743
|
+
"description": {
|
|
2744
|
+
"primary": "storybook",
|
|
2745
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2746
|
+
"confidence": "medium"
|
|
2747
|
+
},
|
|
2748
|
+
"examples": []
|
|
2749
|
+
},
|
|
2750
|
+
{
|
|
2751
|
+
"name": "RowItems",
|
|
2752
|
+
"kind": "component",
|
|
2753
|
+
"description": {
|
|
2754
|
+
"primary": "storybook",
|
|
2755
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2756
|
+
"confidence": "medium"
|
|
2757
|
+
},
|
|
2758
|
+
"examples": []
|
|
2759
|
+
},
|
|
2760
|
+
{
|
|
2761
|
+
"name": "Timeline",
|
|
2762
|
+
"kind": "component",
|
|
2763
|
+
"description": {
|
|
2764
|
+
"primary": "storybook",
|
|
2765
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2766
|
+
"confidence": "medium"
|
|
2767
|
+
},
|
|
2768
|
+
"examples": []
|
|
2769
|
+
},
|
|
2770
|
+
{
|
|
2771
|
+
"name": "ReactCalendarTimeline",
|
|
2772
|
+
"kind": "component",
|
|
2773
|
+
"description": {
|
|
2774
|
+
"primary": "storybook",
|
|
2775
|
+
"storybook": "## Timeline (Calendar Timeline)\n\nLínea de tiempo tipo calendario con grupos, ítems arrastrables y redimensionables, marcadores y cabeceras personalizables.\n\n### Props principales\n- **groups** / **items**: datos de filas e ítems (cada ítem tiene \\",
|
|
2776
|
+
"confidence": "medium"
|
|
2777
|
+
},
|
|
2778
|
+
"examples": []
|
|
2779
|
+
}
|
|
2780
|
+
]
|
|
2781
|
+
}
|
|
2782
|
+
],
|
|
2783
|
+
"styleIndex": {
|
|
2784
|
+
"rules": [
|
|
2785
|
+
"ui-prefix",
|
|
2786
|
+
"typography-pairs",
|
|
2787
|
+
"cn-helper",
|
|
2788
|
+
"no-ui-typography-star",
|
|
2789
|
+
"orbit-tokens-ssot"
|
|
2790
|
+
],
|
|
2791
|
+
"tailwindClasses": [
|
|
2792
|
+
{
|
|
2793
|
+
"class": "ui-bg-fill-brand",
|
|
2794
|
+
"cssVar": "--ui-color-bg-fill-brand-default",
|
|
2795
|
+
"category": "color"
|
|
2796
|
+
},
|
|
2797
|
+
{
|
|
2798
|
+
"class": "ui-text-primary",
|
|
2799
|
+
"cssVar": "--ui-color-text-primary-default",
|
|
2800
|
+
"category": "color"
|
|
2801
|
+
},
|
|
2802
|
+
{
|
|
2803
|
+
"class": "ui-p-16",
|
|
2804
|
+
"cssVar": "--ui-spacing-16",
|
|
2805
|
+
"category": "spacing"
|
|
2806
|
+
},
|
|
2807
|
+
{
|
|
2808
|
+
"class": "ui-rounded-md",
|
|
2809
|
+
"cssVar": "--ui-radius-md",
|
|
2810
|
+
"category": "radius"
|
|
2811
|
+
}
|
|
2812
|
+
]
|
|
2813
|
+
},
|
|
2814
|
+
"changelogRetirements": [],
|
|
2815
|
+
"consumerChecklist": [
|
|
2816
|
+
{
|
|
2817
|
+
"id": "tailwind-prefix",
|
|
2818
|
+
"title": "Prefijo ui- en Tailwind",
|
|
2819
|
+
"body": "Usa clases con prefijo ui- (p. ej. ui-bg-fill-brand, ui-p-16). No utilidades sin prefijo del DS."
|
|
2820
|
+
},
|
|
2821
|
+
{
|
|
2822
|
+
"id": "typography-pairs",
|
|
2823
|
+
"title": "Pares tipografía",
|
|
2824
|
+
"body": "Combina ui-text-body-*-regular con ui-font-body-*-regular. No uses ui-typography-*."
|
|
2825
|
+
},
|
|
2826
|
+
{
|
|
2827
|
+
"id": "cn-helper",
|
|
2828
|
+
"title": "Composición de clases",
|
|
2829
|
+
"body": "Usa cn() desde el paquete para variantes; evita concatenación ad hoc."
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
"id": "orbit-tokens",
|
|
2833
|
+
"title": "Tokens Orbit",
|
|
2834
|
+
"body": "No declares --ui-* ni theme.extend duplicado; consume @imj_media/orbit-tokens."
|
|
2835
|
+
},
|
|
2836
|
+
{
|
|
2837
|
+
"id": "grouped-props",
|
|
2838
|
+
"title": "Props agrupadas",
|
|
2839
|
+
"body": "En organismos extensos, agrupa por dominio (dropZone, constraints, list, events) y migra raíz deprecada gradualmente."
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
"id": "composition-type-2",
|
|
2843
|
+
"title": "Composición (Modal, Accordion)",
|
|
2844
|
+
"body": "Módulos Tipo 2 se usan por piezas; consulta get_composition_recipe antes de aplanar la API."
|
|
2845
|
+
},
|
|
2846
|
+
{
|
|
2847
|
+
"id": "legacy-modules",
|
|
2848
|
+
"title": "Módulos legacy",
|
|
2849
|
+
"body": "LegacyButton, LegacyIcon y Message siguen exportados con legacy:true; evita en código nuevo."
|
|
2850
|
+
},
|
|
2851
|
+
{
|
|
2852
|
+
"id": "jsdoc-imports",
|
|
2853
|
+
"title": "Imports del paquete",
|
|
2854
|
+
"body": "Importa desde @imj_media/ui; usa import type para tipos. Revisa deprecations en get_deprecations."
|
|
2855
|
+
}
|
|
2856
|
+
]
|
|
2857
|
+
}
|