Files
project.linkedcorp.net/frontend/src/components/ContentDialog.jsx
T
Milton Gonzalez 1e6e7fecdd fix(ui): reemplaza panel-debajo-del-listado por DetailPopup de tamaño fijo
El detalle de un item de listado (actividad, departamento, usuario, proyecto nuevo,
catalogo) ya no se apila debajo ni al costado del listado: ahora abre en un popup que
cubre la ventana, deja el listado inactivo detras, nunca se cierra con clic afuera (solo
con el boton Cerrar o una accion explicita del formulario) y mantiene un alto FIJO por
instancia para que cambiar de pestaña interna (Info/Subtareas/Dependencias/Comentarios/
Documentos) no reajuste su tamaño.

De paso corrige un bug real de stacking: ContentDialog no usaba portal a document.body,
así que un dialogo de confirmacion abierto desde dentro de un DetailPopup quedaba oculto
detras de este. Ahora ambos son portales con una jerarquia de z-index explicita
(Flyout 100 < DetailPopup 200 < ContentDialog 250 < Toast 300).

En el detalle de actividad, Subtareas y Dependencias pasan de estar apiladas dentro de la
pestaña Info a ser cada una su propia pestaña.

Regla documentada en project-md-templates/UI-UX-WINDOWS.md (componente DetailPopup) para
que aplique a futuros proyectos de escritorio Windows del grupo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:21:07 -05:00

44 lines
1.7 KiB
React

import { createPortal } from 'react-dom';
import { useUi } from '../context/ui-context.jsx';
import { Button } from './Button.jsx';
const STRIPE_COLOR = { info: 'accent', success: 'success', warning: 'warning', error: 'danger' };
// ContentDialog global — equivalente al AppDialog de la identidad web. Contrato:
// openDialog({ tone, title, message, actions: [{ label, variant, keepOpen, onClick }] })
export function ContentDialogHost() {
const { dialog, closeDialog, t } = useUi();
if (!dialog) return null;
const tone = dialog.tone || 'info';
const actions = dialog.actions?.length ? dialog.actions : [{ label: t('common_close'), variant: 'accent' }];
async function handleClick(action) {
if (action.onClick) await action.onClick();
if (!action.keepOpen) closeDialog();
}
// Regla dura: NUNCA se cierra con clic afuera (a diferencia de Flyout) — solo con un boton.
// Portal a document.body (igual que Flyout/DetailPopup): garantiza que quede SIEMPRE por
// encima de cualquier DetailPopup abierto, sin depender del punto del arbol donde se monta.
return createPortal(
<div className="dialog-overlay">
<div className="dialog-surface">
<div className="dialog-stripe" style={{ background: `rgb(var(--${STRIPE_COLOR[tone]}))` }} />
<div className="dialog-body">
<div className="dialog-title">{dialog.title}</div>
<div className="dialog-message">{dialog.message}</div>
</div>
<div className="dialog-actions">
{actions.map((action, i) => (
<Button key={i} variant={action.variant || 'standard'} onClick={() => handleClick(action)}>
{action.label}
</Button>
))}
</div>
</div>
</div>,
document.body
);
}