@metropolle/design-system 1.2025.1-2.5.1903 → 1.2026.0-1.10.2344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/compat/back.css +12 -0
- package/dist/css/components.css +2594 -144
- package/dist/css/liquid-glass.css +468 -0
- package/dist/react/components/react/Button/Button.d.ts +1 -1
- package/dist/react/components/react/Button/Button.d.ts.map +1 -1
- package/dist/react/components/react/DataTable/DataTable.d.ts.map +1 -1
- package/dist/react/components/react/DataTable/TableHeader.d.ts.map +1 -1
- package/dist/react/components/react/DataTable/TableRow.d.ts.map +1 -1
- package/dist/react/components/react/DataTable/types.d.ts +2 -1
- package/dist/react/components/react/DataTable/types.d.ts.map +1 -1
- package/dist/react/components/react/DetailModal/DetailModal.d.ts +55 -0
- package/dist/react/components/react/DetailModal/DetailModal.d.ts.map +1 -0
- package/dist/react/components/react/DetailModal/index.d.ts +3 -0
- package/dist/react/components/react/DetailModal/index.d.ts.map +1 -0
- package/dist/react/components/react/FormField/FormField.d.ts +26 -0
- package/dist/react/components/react/FormField/FormField.d.ts.map +1 -0
- package/dist/react/components/react/FormField/index.d.ts +3 -0
- package/dist/react/components/react/FormField/index.d.ts.map +1 -0
- package/dist/react/components/react/FormGrid/FormGrid.d.ts +20 -0
- package/dist/react/components/react/FormGrid/FormGrid.d.ts.map +1 -0
- package/dist/react/components/react/FormGrid/index.d.ts +3 -0
- package/dist/react/components/react/FormGrid/index.d.ts.map +1 -0
- package/dist/react/components/react/FormModal/FormModal.d.ts +58 -0
- package/dist/react/components/react/FormModal/FormModal.d.ts.map +1 -0
- package/dist/react/components/react/FormModal/index.d.ts +3 -0
- package/dist/react/components/react/FormModal/index.d.ts.map +1 -0
- package/dist/react/components/react/FormSection/FormSection.d.ts +20 -0
- package/dist/react/components/react/FormSection/FormSection.d.ts.map +1 -0
- package/dist/react/components/react/FormSection/index.d.ts +3 -0
- package/dist/react/components/react/FormSection/index.d.ts.map +1 -0
- package/dist/react/components/react/GlassCard/GlassCard.d.ts +56 -6
- package/dist/react/components/react/GlassCard/GlassCard.d.ts.map +1 -1
- package/dist/react/components/react/GlassCard/index.d.ts +1 -1
- package/dist/react/components/react/GlassCard/index.d.ts.map +1 -1
- package/dist/react/components/react/InfoBox/InfoBox.d.ts +46 -0
- package/dist/react/components/react/InfoBox/InfoBox.d.ts.map +1 -0
- package/dist/react/components/react/InfoBox/index.d.ts +3 -0
- package/dist/react/components/react/InfoBox/index.d.ts.map +1 -0
- package/dist/react/components/react/Modal/Modal.d.ts.map +1 -1
- package/dist/react/components/react/Modal/ModalHeader.d.ts.map +1 -1
- package/dist/react/components/react/ProfileCard/ProfileCard.d.ts +55 -0
- package/dist/react/components/react/ProfileCard/ProfileCard.d.ts.map +1 -0
- package/dist/react/components/react/ProfileCard/index.d.ts +3 -0
- package/dist/react/components/react/ProfileCard/index.d.ts.map +1 -0
- package/dist/react/components/react/Select/Select.d.ts +61 -10
- package/dist/react/components/react/Select/Select.d.ts.map +1 -1
- package/dist/react/components/react/index.d.ts +15 -1
- package/dist/react/components/react/index.d.ts.map +1 -1
- package/dist/react/index.d.ts +32 -18
- package/dist/react/index.esm.js +826 -77
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/index.js +832 -75
- package/dist/react/index.js.map +1 -1
- package/package.json +5 -2
package/dist/react/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import require$$0, { forwardRef, useState, useEffect, useMemo,
|
|
1
|
+
import require$$0, { forwardRef, useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
2
2
|
import { createPortal } from 'react-dom';
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = {exports: {}};
|
|
@@ -1370,12 +1370,47 @@ function cn(...classes) {
|
|
|
1370
1370
|
/**
|
|
1371
1371
|
* Glass Card Component
|
|
1372
1372
|
*
|
|
1373
|
-
* Componente de cartão com efeito glassmorphism
|
|
1374
|
-
*
|
|
1373
|
+
* Componente de cartão com efeito glassmorphism ou Liquid Glass (iOS 26 style).
|
|
1374
|
+
*
|
|
1375
|
+
* @example
|
|
1376
|
+
* ```tsx
|
|
1377
|
+
* // Liquid Glass (novo padrão)
|
|
1378
|
+
* <GlassCard glassStyle="liquid" intensity="md">
|
|
1379
|
+
* Content here
|
|
1380
|
+
* </GlassCard>
|
|
1381
|
+
*
|
|
1382
|
+
* // Glassmorphism tradicional (retrocompatível)
|
|
1383
|
+
* <GlassCard glassStyle="glass" variant="dark">
|
|
1384
|
+
* Content here
|
|
1385
|
+
* </GlassCard>
|
|
1386
|
+
* ```
|
|
1375
1387
|
*/
|
|
1376
|
-
const GlassCard = forwardRef(({
|
|
1388
|
+
const GlassCard = forwardRef(({ glassStyle = 'liquid', intensity = 'md', theme, variant = 'light', blur, opacity, children, className, enableHover = true, cardVariant = 'default', style, ...props }, ref) => {
|
|
1389
|
+
// Resolve theme from new prop or deprecated variant
|
|
1390
|
+
const resolvedTheme = theme ?? variant;
|
|
1391
|
+
// =====================
|
|
1392
|
+
// LIQUID GLASS MODE
|
|
1393
|
+
// =====================
|
|
1394
|
+
if (glassStyle === 'liquid') {
|
|
1395
|
+
// PROC-007: Card variant styles
|
|
1396
|
+
const variantStyles = {
|
|
1397
|
+
default: {},
|
|
1398
|
+
highlight: {
|
|
1399
|
+
borderLeft: '4px solid var(--mds-color-brand-primary, #0055FF)',
|
|
1400
|
+
boxShadow: '0 4px 20px rgba(0, 85, 255, 0.15)'
|
|
1401
|
+
},
|
|
1402
|
+
subtle: {
|
|
1403
|
+
background: 'rgba(255, 255, 255, 0.02)',
|
|
1404
|
+
border: '1px solid rgba(255, 255, 255, 0.05)'
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-liquid-glass', `mds-liquid-glass--${intensity}`, `mds-liquid-glass--${cardVariant}`, !enableHover && 'mds-liquid-glass--no-hover', className), style: { ...variantStyles[cardVariant], ...style }, ...props, children: children }));
|
|
1408
|
+
}
|
|
1409
|
+
// =====================
|
|
1410
|
+
// GLASS MODE (legacy)
|
|
1411
|
+
// =====================
|
|
1377
1412
|
// Default opacities baseadas no design existente
|
|
1378
|
-
const defaultOpacity =
|
|
1413
|
+
const defaultOpacity = resolvedTheme === 'light' ? 0.15 : 0.8;
|
|
1379
1414
|
const finalOpacity = opacity ?? defaultOpacity;
|
|
1380
1415
|
// Use CSS classes for base styles to avoid hydration mismatches
|
|
1381
1416
|
const baseStyles = {
|
|
@@ -1383,12 +1418,16 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1383
1418
|
};
|
|
1384
1419
|
// Only apply custom styles for non-default values
|
|
1385
1420
|
const customStyles = {};
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1421
|
+
// Support legacy blur prop or convert from intensity
|
|
1422
|
+
const resolvedBlur = blur ?? (intensity ? {
|
|
1423
|
+
xs: 2, sm: 4, md: 6, lg: 8, xl: 12
|
|
1424
|
+
}[intensity] : 20);
|
|
1425
|
+
if (resolvedBlur !== 20) {
|
|
1426
|
+
customStyles.backdropFilter = `blur(${resolvedBlur}px)`;
|
|
1427
|
+
customStyles.WebkitBackdropFilter = `blur(${resolvedBlur}px)`;
|
|
1389
1428
|
}
|
|
1390
1429
|
if (opacity !== undefined) {
|
|
1391
|
-
customStyles.background =
|
|
1430
|
+
customStyles.background = resolvedTheme === 'light'
|
|
1392
1431
|
? `rgba(255, 255, 255, ${finalOpacity})`
|
|
1393
1432
|
: `rgba(60, 60, 60, ${finalOpacity})`;
|
|
1394
1433
|
}
|
|
@@ -1403,7 +1442,7 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1403
1442
|
borderColor: 'rgba(255, 255, 255, 0.2)',
|
|
1404
1443
|
background: opacity !== undefined ? `rgba(70, 70, 70, ${finalOpacity})` : undefined,
|
|
1405
1444
|
}
|
|
1406
|
-
}[
|
|
1445
|
+
}[resolvedTheme] : {};
|
|
1407
1446
|
const handleMouseEnter = (e) => {
|
|
1408
1447
|
if (!enableHover)
|
|
1409
1448
|
return;
|
|
@@ -1421,7 +1460,7 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1421
1460
|
});
|
|
1422
1461
|
props.onMouseLeave?.(e);
|
|
1423
1462
|
};
|
|
1424
|
-
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-glass-card', `mds-glass-card--${
|
|
1463
|
+
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-glass-card', `mds-glass-card--${resolvedTheme}`, !enableHover && 'mds-glass-card--no-hover', className), style: {
|
|
1425
1464
|
...baseStyles,
|
|
1426
1465
|
...customStyles,
|
|
1427
1466
|
...style
|
|
@@ -1429,6 +1468,125 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1429
1468
|
});
|
|
1430
1469
|
GlassCard.displayName = 'GlassCard';
|
|
1431
1470
|
|
|
1471
|
+
// Default placeholder avatar - adapts to theme with high transparency
|
|
1472
|
+
const getPlaceholderAvatar = (isDark) => {
|
|
1473
|
+
const bgColor = isDark ? 'rgba(26, 26, 46, 0.15)' : 'rgba(255, 255, 255, 0.1)';
|
|
1474
|
+
const fgColor = isDark ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.06)';
|
|
1475
|
+
return 'data:image/svg+xml,' + encodeURIComponent(`
|
|
1476
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
|
1477
|
+
<rect width="200" height="200" fill="${bgColor}"/>
|
|
1478
|
+
<circle cx="100" cy="80" r="40" fill="${fgColor}"/>
|
|
1479
|
+
<ellipse cx="100" cy="180" rx="60" ry="50" fill="${fgColor}"/>
|
|
1480
|
+
</svg>
|
|
1481
|
+
`);
|
|
1482
|
+
};
|
|
1483
|
+
// =============================================================================
|
|
1484
|
+
// Icons
|
|
1485
|
+
// =============================================================================
|
|
1486
|
+
const Icons = {
|
|
1487
|
+
shield: (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", children: jsxRuntimeExports.jsx("path", { d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z", fill: "currentColor" }) })),
|
|
1488
|
+
plus: (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", children: jsxRuntimeExports.jsx("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z", fill: "currentColor" }) })),
|
|
1489
|
+
instagram: jsxRuntimeExports.jsx("path", { d: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z" }),
|
|
1490
|
+
x: jsxRuntimeExports.jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }),
|
|
1491
|
+
linkedin: jsxRuntimeExports.jsx("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }),
|
|
1492
|
+
website: jsxRuntimeExports.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" }),
|
|
1493
|
+
};
|
|
1494
|
+
function SocialLink({ href, title, icon }) {
|
|
1495
|
+
const iconPath = Icons[icon];
|
|
1496
|
+
if (!iconPath || typeof iconPath === 'object')
|
|
1497
|
+
return null;
|
|
1498
|
+
return (jsxRuntimeExports.jsx("a", { href: href, className: "mds-profile-card__social-link", title: title, target: "_blank", rel: "noopener noreferrer", children: jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", children: iconPath }) }));
|
|
1499
|
+
}
|
|
1500
|
+
function StatItem({ label, verified }) {
|
|
1501
|
+
return (jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__stat-item", children: [jsxRuntimeExports.jsx("span", { className: "mds-profile-card__stat-label", children: label }), jsxRuntimeExports.jsx("span", { className: `mds-profile-card__stat-value ${verified ? 'mds-profile-card__stat-value--verified' : ''}`, children: verified ? 'Verified' : 'Not Verified' })] }));
|
|
1502
|
+
}
|
|
1503
|
+
// =============================================================================
|
|
1504
|
+
// Main Component
|
|
1505
|
+
// =============================================================================
|
|
1506
|
+
function ProfileCard({ user, variant = 'full', photoWidth, showSocial = false, socialLinks, showRotatingInfo = false, photoSlot, className = '', onSocialClick, }) {
|
|
1507
|
+
const [showVerifiedPopup, setShowVerifiedPopup] = useState(false);
|
|
1508
|
+
const [showSocialPopup, setShowSocialPopup] = useState(false);
|
|
1509
|
+
const [currentInfoIndex, setCurrentInfoIndex] = useState(0);
|
|
1510
|
+
const [isDarkTheme, setIsDarkTheme] = useState(true);
|
|
1511
|
+
const verifiedRef = useRef(null);
|
|
1512
|
+
const socialRef = useRef(null);
|
|
1513
|
+
// Calculate photo width based on variant
|
|
1514
|
+
const computedPhotoWidth = photoWidth ?? (variant === 'full' ? 280 : 200);
|
|
1515
|
+
// Detect theme
|
|
1516
|
+
useEffect(() => {
|
|
1517
|
+
const checkTheme = () => {
|
|
1518
|
+
const theme = document.documentElement.getAttribute('data-theme');
|
|
1519
|
+
setIsDarkTheme(theme !== 'light');
|
|
1520
|
+
};
|
|
1521
|
+
checkTheme();
|
|
1522
|
+
const observer = new MutationObserver((mutations) => {
|
|
1523
|
+
mutations.forEach((mutation) => {
|
|
1524
|
+
if (mutation.attributeName === 'data-theme') {
|
|
1525
|
+
checkTheme();
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
});
|
|
1529
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
1530
|
+
return () => observer.disconnect();
|
|
1531
|
+
}, []);
|
|
1532
|
+
// Dynamic info texts for rotating display
|
|
1533
|
+
const infoTexts = [
|
|
1534
|
+
`Member since ${new Date(user.created_at).getFullYear()}`,
|
|
1535
|
+
...(user.verified >= 1 ? ['Email Verified'] : []),
|
|
1536
|
+
...(user.verified >= 2 ? ['Identity Verified'] : []),
|
|
1537
|
+
...(user.verified >= 3 ? ['Professional Verified'] : []),
|
|
1538
|
+
];
|
|
1539
|
+
// Rotate info text
|
|
1540
|
+
useEffect(() => {
|
|
1541
|
+
if (!showRotatingInfo)
|
|
1542
|
+
return;
|
|
1543
|
+
const interval = setInterval(() => {
|
|
1544
|
+
setCurrentInfoIndex((prev) => (prev + 1) % infoTexts.length);
|
|
1545
|
+
}, 10000);
|
|
1546
|
+
return () => clearInterval(interval);
|
|
1547
|
+
}, [infoTexts.length, showRotatingInfo]);
|
|
1548
|
+
// Close popups on click outside
|
|
1549
|
+
useEffect(() => {
|
|
1550
|
+
const handleClickOutside = (e) => {
|
|
1551
|
+
if (verifiedRef.current && !verifiedRef.current.contains(e.target)) {
|
|
1552
|
+
setShowVerifiedPopup(false);
|
|
1553
|
+
}
|
|
1554
|
+
if (socialRef.current && !socialRef.current.contains(e.target)) {
|
|
1555
|
+
setShowSocialPopup(false);
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
document.addEventListener('click', handleClickOutside);
|
|
1559
|
+
return () => document.removeEventListener('click', handleClickOutside);
|
|
1560
|
+
}, []);
|
|
1561
|
+
// Get display values
|
|
1562
|
+
const displayName = user.full_name || user.username || 'User';
|
|
1563
|
+
const profession = user.profession_name || user.profession_code || '';
|
|
1564
|
+
const getLocation = () => {
|
|
1565
|
+
if (!user.city_code && !user.state_code && !user.country_code)
|
|
1566
|
+
return null;
|
|
1567
|
+
const city = user.city_name || user.city_code?.toUpperCase() || '';
|
|
1568
|
+
const state = user.state_code?.toUpperCase() || '';
|
|
1569
|
+
const country = user.country_name || user.country_code?.toUpperCase() || '';
|
|
1570
|
+
const parts = [city, state, country].filter(Boolean);
|
|
1571
|
+
return parts.join(', ');
|
|
1572
|
+
};
|
|
1573
|
+
const memberSince = new Date(user.created_at).getFullYear().toString();
|
|
1574
|
+
const photoUrl = user.photo_url_medium || user.photo_url_full || getPlaceholderAvatar(isDarkTheme);
|
|
1575
|
+
return (jsxRuntimeExports.jsxs("article", { className: `mds-profile-card ${className}`, style: { '--mds-profile-card-photo-width': `${computedPhotoWidth}px` }, children: [jsxRuntimeExports.jsx("div", { className: "mds-profile-card__grain" }), jsxRuntimeExports.jsx("div", { className: "mds-profile-card__photo", children: photoSlot ? (jsxRuntimeExports.jsx("div", { className: "mds-profile-card__photo-slot", children: photoSlot })) : (jsxRuntimeExports.jsx("img", { src: photoUrl, alt: displayName, className: "mds-profile-card__avatar" })) }), jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__content", children: [jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__identity", children: [jsxRuntimeExports.jsx("h1", { className: "mds-profile-card__name", children: displayName.toUpperCase() }), variant === 'full' && profession && (jsxRuntimeExports.jsx("p", { className: "mds-profile-card__profession", children: profession.toUpperCase() })), variant === 'compact' && (jsxRuntimeExports.jsx("p", { className: "mds-profile-card__username", children: user.username }))] }), jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__details", children: [variant === 'full' && getLocation() && (jsxRuntimeExports.jsx("p", { className: "mds-profile-card__location", children: getLocation() })), variant === 'full' && (jsxRuntimeExports.jsx("span", { className: "mds-profile-card__username-detail", children: user.username })), variant === 'compact' && user.email && (jsxRuntimeExports.jsx("p", { className: "mds-profile-card__email", children: user.email })), variant === 'compact' && (jsxRuntimeExports.jsxs("span", { className: "mds-profile-card__member", children: ["Member since ", memberSince] }))] }), variant === 'compact' && (jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__verification", children: [jsxRuntimeExports.jsxs("button", { className: "mds-profile-card__verified-badge", title: `Verification Level ${user.verified}`, onClick: (e) => {
|
|
1576
|
+
e.stopPropagation();
|
|
1577
|
+
setShowVerifiedPopup(!showVerifiedPopup);
|
|
1578
|
+
}, children: [Icons.shield, jsxRuntimeExports.jsxs("span", { children: ["Level ", user.verified] })] }), jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__dots", children: [jsxRuntimeExports.jsx("span", { className: `mds-profile-card__dot ${user.verified >= 1 ? 'active' : ''}`, title: "Email Verified" }), jsxRuntimeExports.jsx("span", { className: `mds-profile-card__dot ${user.verified >= 2 ? 'active' : ''}`, title: "Identity Verified" }), jsxRuntimeExports.jsx("span", { className: `mds-profile-card__dot ${user.verified >= 3 ? 'active' : ''}`, title: "Professional Verified" })] })] })), showSocial && (jsxRuntimeExports.jsxs("div", { ref: socialRef, className: "mds-profile-card__social", children: [jsxRuntimeExports.jsx("button", { className: "mds-profile-card__social-trigger", onClick: (e) => {
|
|
1579
|
+
e.stopPropagation();
|
|
1580
|
+
setShowSocialPopup(!showSocialPopup);
|
|
1581
|
+
setShowVerifiedPopup(false);
|
|
1582
|
+
onSocialClick?.();
|
|
1583
|
+
}, "aria-label": "Show social links", children: Icons.plus }), showSocialPopup && socialLinks && (jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__social-popup", children: [socialLinks.instagram && jsxRuntimeExports.jsx(SocialLink, { href: socialLinks.instagram, title: "Instagram", icon: "instagram" }), socialLinks.x && jsxRuntimeExports.jsx(SocialLink, { href: socialLinks.x, title: "X", icon: "x" }), socialLinks.linkedin && jsxRuntimeExports.jsx(SocialLink, { href: socialLinks.linkedin, title: "LinkedIn", icon: "linkedin" }), socialLinks.website && jsxRuntimeExports.jsx(SocialLink, { href: socialLinks.website, title: "Website", icon: "website" })] }))] })), variant === 'full' && (jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__dynamic-group", children: [showRotatingInfo && (jsxRuntimeExports.jsx("span", { className: "mds-profile-card__dynamic-info", children: infoTexts[currentInfoIndex] })), jsxRuntimeExports.jsxs("div", { ref: verifiedRef, className: "mds-profile-card__verified-section", children: [jsxRuntimeExports.jsx("button", { className: "mds-profile-card__verified-trigger", onClick: (e) => {
|
|
1584
|
+
e.stopPropagation();
|
|
1585
|
+
setShowVerifiedPopup(!showVerifiedPopup);
|
|
1586
|
+
setShowSocialPopup(false);
|
|
1587
|
+
}, title: "Verification Status", children: Icons.shield }), showVerifiedPopup && (jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__verified-popup", children: [jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__verified-header", children: ["Verification Level ", user.verified] }), jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__verified-stats", children: [jsxRuntimeExports.jsx(StatItem, { label: "Email", verified: user.verified >= 1 }), jsxRuntimeExports.jsx(StatItem, { label: "Identity", verified: user.verified >= 2 }), jsxRuntimeExports.jsx(StatItem, { label: "Professional", verified: user.verified >= 3 })] }), jsxRuntimeExports.jsxs("div", { className: "mds-profile-card__verified-date", children: ["Since ", memberSince] })] }))] }), showRotatingInfo && (jsxRuntimeExports.jsx("div", { className: "mds-profile-card__info-dots", children: infoTexts.map((_, index) => (jsxRuntimeExports.jsx("span", { className: `mds-profile-card__info-dot ${index === currentInfoIndex ? 'active' : ''}` }, index))) }))] }))] })] }));
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1432
1590
|
const variantElementMap = {
|
|
1433
1591
|
h1: 'h1',
|
|
1434
1592
|
h2: 'h2',
|
|
@@ -1493,22 +1651,241 @@ const LoadingSpinner = () => (jsxRuntimeExports.jsxs("svg", { className: "mds-sp
|
|
|
1493
1651
|
/**
|
|
1494
1652
|
* Select Component (Design System)
|
|
1495
1653
|
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1654
|
+
* Custom dropdown select that renders consistently across all browsers.
|
|
1655
|
+
* Unlike native <select>, this component renders the dropdown via JavaScript,
|
|
1656
|
+
* ensuring proper theming support on Edge/Chrome Windows.
|
|
1657
|
+
*
|
|
1658
|
+
* @example
|
|
1659
|
+
* ```tsx
|
|
1660
|
+
* <Select
|
|
1661
|
+
* options={[
|
|
1662
|
+
* { label: 'Option 1', value: '1' },
|
|
1663
|
+
* { label: 'Option 2', value: '2' },
|
|
1664
|
+
* ]}
|
|
1665
|
+
* value={selectedValue}
|
|
1666
|
+
* onChange={setSelectedValue}
|
|
1667
|
+
* placeholder="Select an option..."
|
|
1668
|
+
* />
|
|
1669
|
+
* ```
|
|
1500
1670
|
*/
|
|
1501
|
-
const Select = forwardRef(({ options,
|
|
1502
|
-
const
|
|
1503
|
-
const
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1671
|
+
const Select = forwardRef(({ options, value, onChange, placeholder = 'Select...', variant = 'themed', size = 'md', disabled = false, loading = false, error = false, className, dropdownClassName, id, name, 'aria-label': ariaLabel, fullWidth = false, searchable = false, searchPlaceholder = 'Search...', maxHeight = 300, zIndex = 1050, }, ref) => {
|
|
1672
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1673
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
1674
|
+
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
1675
|
+
const [mounted, setMounted] = useState(false);
|
|
1676
|
+
const triggerRef = useRef(null);
|
|
1677
|
+
const dropdownRef = useRef(null);
|
|
1678
|
+
const searchInputRef = useRef(null);
|
|
1679
|
+
const listRef = useRef(null);
|
|
1680
|
+
// Combine refs
|
|
1681
|
+
const combinedRef = (el) => {
|
|
1682
|
+
triggerRef.current = el;
|
|
1683
|
+
if (typeof ref === 'function') {
|
|
1684
|
+
ref(el);
|
|
1685
|
+
}
|
|
1686
|
+
else if (ref) {
|
|
1687
|
+
ref.current = el;
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
// Client-side only
|
|
1691
|
+
useEffect(() => {
|
|
1692
|
+
setMounted(true);
|
|
1693
|
+
}, []);
|
|
1694
|
+
// Filter options based on search
|
|
1695
|
+
const filteredOptions = useMemo(() => {
|
|
1696
|
+
if (!searchTerm)
|
|
1697
|
+
return options;
|
|
1698
|
+
const term = searchTerm.toLowerCase();
|
|
1699
|
+
return options.filter(opt => {
|
|
1700
|
+
const label = typeof opt.label === 'string' ? opt.label : String(opt.value);
|
|
1701
|
+
return label.toLowerCase().includes(term);
|
|
1702
|
+
});
|
|
1703
|
+
}, [options, searchTerm]);
|
|
1704
|
+
// Get selected option label
|
|
1705
|
+
const selectedOption = useMemo(() => {
|
|
1706
|
+
return options.find(opt => opt.value === value);
|
|
1707
|
+
}, [options, value]);
|
|
1708
|
+
// Handle dropdown positioning
|
|
1709
|
+
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 });
|
|
1710
|
+
const updateDropdownPosition = useCallback(() => {
|
|
1711
|
+
if (!triggerRef.current)
|
|
1712
|
+
return;
|
|
1713
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
1714
|
+
const viewportHeight = window.innerHeight;
|
|
1715
|
+
const spaceBelow = viewportHeight - rect.bottom;
|
|
1716
|
+
const spaceAbove = rect.top;
|
|
1717
|
+
// Determine if dropdown should open above or below
|
|
1718
|
+
const dropdownHeight = Math.min(maxHeight, filteredOptions.length * 40 + (searchable ? 48 : 0));
|
|
1719
|
+
const openAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;
|
|
1720
|
+
setDropdownPosition({
|
|
1721
|
+
top: openAbove ? rect.top - dropdownHeight : rect.bottom + 4,
|
|
1722
|
+
left: rect.left,
|
|
1723
|
+
width: rect.width,
|
|
1724
|
+
});
|
|
1725
|
+
}, [maxHeight, filteredOptions.length, searchable]);
|
|
1726
|
+
// Open dropdown
|
|
1727
|
+
const openDropdown = useCallback(() => {
|
|
1728
|
+
if (disabled || loading)
|
|
1729
|
+
return;
|
|
1730
|
+
updateDropdownPosition();
|
|
1731
|
+
setIsOpen(true);
|
|
1732
|
+
setSearchTerm('');
|
|
1733
|
+
setHighlightedIndex(value ? filteredOptions.findIndex(opt => opt.value === value) : 0);
|
|
1734
|
+
}, [disabled, loading, updateDropdownPosition, value, filteredOptions]);
|
|
1735
|
+
// Close dropdown
|
|
1736
|
+
const closeDropdown = useCallback(() => {
|
|
1737
|
+
setIsOpen(false);
|
|
1738
|
+
setSearchTerm('');
|
|
1739
|
+
setHighlightedIndex(-1);
|
|
1740
|
+
triggerRef.current?.focus();
|
|
1741
|
+
}, []);
|
|
1742
|
+
// Handle option select
|
|
1743
|
+
const handleSelect = useCallback((optionValue) => {
|
|
1744
|
+
// Safety check: ensure we're passing a string, not an object
|
|
1745
|
+
const safeValue = typeof optionValue === 'string' ? optionValue : String(optionValue);
|
|
1746
|
+
onChange?.(safeValue);
|
|
1747
|
+
closeDropdown();
|
|
1748
|
+
}, [onChange, closeDropdown]);
|
|
1749
|
+
// Keyboard navigation
|
|
1750
|
+
const handleKeyDown = useCallback((e) => {
|
|
1751
|
+
if (disabled || loading)
|
|
1752
|
+
return;
|
|
1753
|
+
switch (e.key) {
|
|
1754
|
+
case 'Enter':
|
|
1755
|
+
case ' ':
|
|
1756
|
+
e.preventDefault();
|
|
1757
|
+
if (isOpen && highlightedIndex >= 0 && filteredOptions[highlightedIndex]) {
|
|
1758
|
+
const opt = filteredOptions[highlightedIndex];
|
|
1759
|
+
if (!opt.disabled) {
|
|
1760
|
+
handleSelect(opt.value);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
else if (!isOpen) {
|
|
1764
|
+
openDropdown();
|
|
1765
|
+
}
|
|
1766
|
+
break;
|
|
1767
|
+
case 'ArrowDown':
|
|
1768
|
+
e.preventDefault();
|
|
1769
|
+
if (!isOpen) {
|
|
1770
|
+
openDropdown();
|
|
1771
|
+
}
|
|
1772
|
+
else {
|
|
1773
|
+
setHighlightedIndex(prev => {
|
|
1774
|
+
const next = prev + 1;
|
|
1775
|
+
return next >= filteredOptions.length ? 0 : next;
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
break;
|
|
1779
|
+
case 'ArrowUp':
|
|
1780
|
+
e.preventDefault();
|
|
1781
|
+
if (isOpen) {
|
|
1782
|
+
setHighlightedIndex(prev => {
|
|
1783
|
+
const next = prev - 1;
|
|
1784
|
+
return next < 0 ? filteredOptions.length - 1 : next;
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
break;
|
|
1788
|
+
case 'Escape':
|
|
1789
|
+
e.preventDefault();
|
|
1790
|
+
closeDropdown();
|
|
1791
|
+
break;
|
|
1792
|
+
case 'Tab':
|
|
1793
|
+
if (isOpen) {
|
|
1794
|
+
closeDropdown();
|
|
1795
|
+
}
|
|
1796
|
+
break;
|
|
1797
|
+
case 'Home':
|
|
1798
|
+
if (isOpen) {
|
|
1799
|
+
e.preventDefault();
|
|
1800
|
+
setHighlightedIndex(0);
|
|
1801
|
+
}
|
|
1802
|
+
break;
|
|
1803
|
+
case 'End':
|
|
1804
|
+
if (isOpen) {
|
|
1805
|
+
e.preventDefault();
|
|
1806
|
+
setHighlightedIndex(filteredOptions.length - 1);
|
|
1807
|
+
}
|
|
1808
|
+
break;
|
|
1809
|
+
}
|
|
1810
|
+
}, [disabled, loading, isOpen, highlightedIndex, filteredOptions, handleSelect, openDropdown, closeDropdown]);
|
|
1811
|
+
// Click outside to close
|
|
1812
|
+
useEffect(() => {
|
|
1813
|
+
if (!isOpen)
|
|
1814
|
+
return;
|
|
1815
|
+
const handleClickOutside = (e) => {
|
|
1816
|
+
if (triggerRef.current?.contains(e.target) ||
|
|
1817
|
+
dropdownRef.current?.contains(e.target)) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
closeDropdown();
|
|
1821
|
+
};
|
|
1822
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
1823
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
1824
|
+
}, [isOpen, closeDropdown]);
|
|
1825
|
+
// Update position on scroll/resize
|
|
1826
|
+
useEffect(() => {
|
|
1827
|
+
if (!isOpen)
|
|
1828
|
+
return;
|
|
1829
|
+
const handleUpdate = () => updateDropdownPosition();
|
|
1830
|
+
window.addEventListener('scroll', handleUpdate, true);
|
|
1831
|
+
window.addEventListener('resize', handleUpdate);
|
|
1832
|
+
return () => {
|
|
1833
|
+
window.removeEventListener('scroll', handleUpdate, true);
|
|
1834
|
+
window.removeEventListener('resize', handleUpdate);
|
|
1835
|
+
};
|
|
1836
|
+
}, [isOpen, updateDropdownPosition]);
|
|
1837
|
+
// Focus search input when dropdown opens
|
|
1838
|
+
useEffect(() => {
|
|
1839
|
+
if (isOpen && searchable && searchInputRef.current) {
|
|
1840
|
+
searchInputRef.current.focus();
|
|
1841
|
+
}
|
|
1842
|
+
}, [isOpen, searchable]);
|
|
1843
|
+
// Scroll highlighted option into view
|
|
1844
|
+
useEffect(() => {
|
|
1845
|
+
if (!isOpen || highlightedIndex < 0 || !listRef.current)
|
|
1846
|
+
return;
|
|
1847
|
+
const highlighted = listRef.current.children[highlightedIndex];
|
|
1848
|
+
if (highlighted) {
|
|
1849
|
+
highlighted.scrollIntoView({ block: 'nearest' });
|
|
1850
|
+
}
|
|
1851
|
+
}, [isOpen, highlightedIndex]);
|
|
1852
|
+
// Size classes
|
|
1853
|
+
const sizeClasses = {
|
|
1854
|
+
sm: 'mds-select--sm',
|
|
1855
|
+
md: 'mds-select--md',
|
|
1856
|
+
lg: 'mds-select--lg',
|
|
1857
|
+
};
|
|
1858
|
+
// Variant classes
|
|
1859
|
+
const variantClasses = {
|
|
1860
|
+
base: 'mds-select--base',
|
|
1861
|
+
themed: 'mds-select--themed',
|
|
1862
|
+
dashboard: 'mds-select--themed',
|
|
1863
|
+
};
|
|
1864
|
+
const triggerClasses = cn('mds-select-trigger', sizeClasses[size], variantClasses[variant], isOpen && 'mds-select-trigger--open', disabled && 'mds-select-trigger--disabled', loading && 'mds-select-trigger--loading', error && 'mds-select-trigger--error', fullWidth && 'mds-select-trigger--full-width', className);
|
|
1865
|
+
const dropdownClasses = cn('mds-select-dropdown', variantClasses[variant], dropdownClassName);
|
|
1866
|
+
// Hidden input for form submission
|
|
1867
|
+
const hiddenInput = name ? (jsxRuntimeExports.jsx("input", { type: "hidden", name: name, value: value || '' })) : null;
|
|
1868
|
+
// Dropdown portal content
|
|
1869
|
+
const dropdownContent = isOpen && mounted ? createPortal(jsxRuntimeExports.jsxs("div", { ref: dropdownRef, className: dropdownClasses, style: {
|
|
1870
|
+
position: 'fixed',
|
|
1871
|
+
top: dropdownPosition.top,
|
|
1872
|
+
left: dropdownPosition.left,
|
|
1873
|
+
width: dropdownPosition.width,
|
|
1874
|
+
maxHeight,
|
|
1875
|
+
zIndex,
|
|
1876
|
+
}, role: "listbox", "aria-label": ariaLabel || placeholder, children: [searchable && (jsxRuntimeExports.jsxs("div", { className: "mds-select-search", children: [jsxRuntimeExports.jsx("input", { ref: searchInputRef, type: "text", className: "mds-select-search__input", placeholder: searchPlaceholder, value: searchTerm, onChange: (e) => {
|
|
1877
|
+
setSearchTerm(e.target.value);
|
|
1878
|
+
setHighlightedIndex(0);
|
|
1879
|
+
}, onKeyDown: handleKeyDown, "aria-label": "Search options" }), jsxRuntimeExports.jsx("svg", { className: "mds-select-search__icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z", clipRule: "evenodd" }) })] })), jsxRuntimeExports.jsx("ul", { ref: listRef, className: "mds-select-options", children: filteredOptions.length === 0 ? (jsxRuntimeExports.jsx("li", { className: "mds-select-option mds-select-option--empty", children: "No options found" })) : (filteredOptions.map((option, index) => (jsxRuntimeExports.jsxs("li", { className: cn('mds-select-option', option.value === value && 'mds-select-option--selected', index === highlightedIndex && 'mds-select-option--highlighted', option.disabled && 'mds-select-option--disabled'), role: "option", "aria-selected": option.value === value, "aria-disabled": option.disabled, onClick: () => {
|
|
1880
|
+
if (!option.disabled) {
|
|
1881
|
+
handleSelect(option.value);
|
|
1882
|
+
}
|
|
1883
|
+
}, onMouseEnter: () => {
|
|
1884
|
+
if (!option.disabled) {
|
|
1885
|
+
setHighlightedIndex(index);
|
|
1886
|
+
}
|
|
1887
|
+
}, children: [jsxRuntimeExports.jsx("span", { className: "mds-select-option__label", children: option.label }), option.value === value && (jsxRuntimeExports.jsx("svg", { className: "mds-select-option__check", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }))] }, option.value)))) })] }), document.body) : null;
|
|
1888
|
+
return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [hiddenInput, jsxRuntimeExports.jsxs("button", { ref: combinedRef, type: "button", id: id, className: triggerClasses, onClick: () => isOpen ? closeDropdown() : openDropdown(), onKeyDown: handleKeyDown, disabled: disabled || loading, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel, "aria-invalid": error, children: [jsxRuntimeExports.jsx("span", { className: cn('mds-select-trigger__value', !selectedOption && 'mds-select-trigger__placeholder'), children: loading ? 'Loading...' : (selectedOption?.label || placeholder) }), jsxRuntimeExports.jsx("span", { className: "mds-select-trigger__icon", children: loading ? (jsxRuntimeExports.jsx("svg", { className: "mds-select-spinner", viewBox: "0 0 24 24", fill: "none", children: jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeDasharray: "32", strokeDashoffset: "32", children: jsxRuntimeExports.jsx("animate", { attributeName: "stroke-dashoffset", values: "32;0", dur: "1s", repeatCount: "indefinite" }) }) })) : (jsxRuntimeExports.jsx("svg", { className: "mds-select-chevron", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })) })] }), dropdownContent] }));
|
|
1512
1889
|
});
|
|
1513
1890
|
Select.displayName = 'Select';
|
|
1514
1891
|
|
|
@@ -1581,36 +1958,43 @@ function ThemeToggle({ size = 'md', className = '', disabled = false, onChange,
|
|
|
1581
1958
|
return (jsxRuntimeExports.jsx("button", { onClick: toggleTheme, className: buttonClasses, disabled: disabled, type: "button", "aria-pressed": isDark, "aria-label": `Switch to ${isDark ? 'light' : 'dark'} mode`, title: `Switch to ${isDark ? 'light' : 'dark'} mode`, "data-theme": isDark ? 'dark' : 'light', style: buttonStyle }));
|
|
1582
1959
|
}
|
|
1583
1960
|
|
|
1584
|
-
const TableHeader = ({ columns, gridTemplate, onSort, sortColumn, sortDirection }) => {
|
|
1585
|
-
return (jsxRuntimeExports.
|
|
1961
|
+
const TableHeader = ({ columns, gridTemplate, onSort, sortColumn, sortDirection, hasActions = false }) => {
|
|
1962
|
+
return (jsxRuntimeExports.jsxs("div", { role: "rowgroup", style: {
|
|
1586
1963
|
display: 'grid',
|
|
1587
1964
|
gridTemplateColumns: gridTemplate,
|
|
1588
1965
|
gap: '16px',
|
|
1589
1966
|
padding: '16px 20px',
|
|
1590
1967
|
borderBottom: '1px solid var(--border-color)',
|
|
1591
1968
|
backgroundColor: 'rgba(255, 255, 255, 0.05)'
|
|
1592
|
-
}, children: columns.map((column) => (jsxRuntimeExports.jsxs("div", { role: "columnheader", style: {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1969
|
+
}, children: [columns.map((column) => (jsxRuntimeExports.jsxs("div", { role: "columnheader", style: {
|
|
1970
|
+
color: 'var(--text-primary)',
|
|
1971
|
+
fontWeight: '500',
|
|
1972
|
+
fontSize: '14px',
|
|
1973
|
+
display: 'flex',
|
|
1974
|
+
alignItems: 'center',
|
|
1975
|
+
justifyContent: column.align === 'center' ? 'center' :
|
|
1976
|
+
column.align === 'right' ? 'flex-end' : 'flex-start',
|
|
1977
|
+
cursor: column.sortable && onSort ? 'pointer' : 'default',
|
|
1978
|
+
gap: '4px',
|
|
1979
|
+
transition: 'color 0.2s ease'
|
|
1980
|
+
}, onClick: () => column.sortable && onSort && onSort(column.key), onMouseEnter: (e) => {
|
|
1981
|
+
if (column.sortable && onSort) {
|
|
1982
|
+
e.currentTarget.style.color = '#ffffff';
|
|
1983
|
+
}
|
|
1984
|
+
}, onMouseLeave: (e) => {
|
|
1985
|
+
e.currentTarget.style.color = 'var(--text-primary)';
|
|
1986
|
+
}, children: [column.label, column.sortable && onSort && (jsxRuntimeExports.jsx("span", { style: {
|
|
1987
|
+
fontSize: '12px',
|
|
1988
|
+
opacity: sortColumn === column.key ? 1 : 0.5
|
|
1989
|
+
}, children: sortColumn === column.key ?
|
|
1990
|
+
(sortDirection === 'asc' ? '↑' : '↓') : '↕' }))] }, column.key))), hasActions && (jsxRuntimeExports.jsx("div", { role: "columnheader", style: {
|
|
1991
|
+
color: 'var(--text-primary)',
|
|
1992
|
+
fontWeight: '500',
|
|
1993
|
+
fontSize: '14px',
|
|
1994
|
+
display: 'flex',
|
|
1995
|
+
alignItems: 'center',
|
|
1996
|
+
justifyContent: 'center'
|
|
1997
|
+
}, children: "Actions" }))] }));
|
|
1614
1998
|
};
|
|
1615
1999
|
|
|
1616
2000
|
const TableRow = ({ item, index, columns, actions = [], gridTemplate, isLast, variant, onActionClick }) => {
|
|
@@ -1648,10 +2032,9 @@ const TableRow = ({ item, index, columns, actions = [], gridTemplate, isLast, va
|
|
|
1648
2032
|
const isLoading = action.loading?.(item) || false;
|
|
1649
2033
|
return (jsxRuntimeExports.jsxs("button", { onClick: () => !isDisabled && !isLoading && onActionClick(action, item), disabled: isDisabled || isLoading, style: {
|
|
1650
2034
|
background: 'none',
|
|
1651
|
-
border:
|
|
1652
|
-
'1px solid var(--border-color)',
|
|
2035
|
+
border: 'none',
|
|
1653
2036
|
borderRadius: '6px',
|
|
1654
|
-
padding: '6px
|
|
2037
|
+
padding: '6px 8px',
|
|
1655
2038
|
color: action.variant === 'danger' ? '#f87171' : 'var(--text-primary)',
|
|
1656
2039
|
fontSize: '12px',
|
|
1657
2040
|
cursor: isDisabled || isLoading ? 'not-allowed' : 'pointer',
|
|
@@ -1665,18 +2048,14 @@ const TableRow = ({ item, index, columns, actions = [], gridTemplate, isLast, va
|
|
|
1665
2048
|
if (!isDisabled && !isLoading) {
|
|
1666
2049
|
if (action.variant === 'danger') {
|
|
1667
2050
|
e.currentTarget.style.backgroundColor = 'rgba(239, 68, 68, 0.1)';
|
|
1668
|
-
e.currentTarget.style.borderColor = 'rgba(239, 68, 68, 0.5)';
|
|
1669
2051
|
}
|
|
1670
2052
|
else {
|
|
1671
2053
|
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
|
|
1672
|
-
e.currentTarget.style.borderColor = 'var(--text-primary)';
|
|
1673
2054
|
}
|
|
1674
2055
|
}
|
|
1675
2056
|
}, onMouseLeave: (e) => {
|
|
1676
2057
|
if (!isDisabled && !isLoading) {
|
|
1677
2058
|
e.currentTarget.style.backgroundColor = 'transparent';
|
|
1678
|
-
e.currentTarget.style.borderColor = action.variant === 'danger' ?
|
|
1679
|
-
'rgba(239, 68, 68, 0.3)' : 'var(--border-color)';
|
|
1680
2059
|
}
|
|
1681
2060
|
}, children: [action.icon && action.icon, action.label] }, action.key));
|
|
1682
2061
|
}) }))] }));
|
|
@@ -1776,7 +2155,7 @@ const DataTable = ({ data, columns, loading = false, searchTerm = '', actions =
|
|
|
1776
2155
|
color: 'var(--text-secondary)',
|
|
1777
2156
|
fontSize: '14px',
|
|
1778
2157
|
borderBottom: '1px solid var(--border-color)'
|
|
1779
|
-
}, children: ["Mostrando", ' ', jsxRuntimeExports.jsx("span", { style: { fontWeight: '500', color: 'var(--text-primary)' }, children: filteredData.length }), ' ', "de", ' ', jsxRuntimeExports.jsx("span", { style: { fontWeight: '500', color: 'var(--text-primary)' }, children: data.length }), ' ', "itens"] })), jsxRuntimeExports.jsx(TableHeader, { columns: columns, gridTemplate: gridTemplate, onSort: onSort ? handleSort : undefined, sortColumn: sortColumn, sortDirection: sortDirection }), jsxRuntimeExports.jsx("div", { role: "rowgroup", style: {
|
|
2158
|
+
}, children: ["Mostrando", ' ', jsxRuntimeExports.jsx("span", { style: { fontWeight: '500', color: 'var(--text-primary)' }, children: filteredData.length }), ' ', "de", ' ', jsxRuntimeExports.jsx("span", { style: { fontWeight: '500', color: 'var(--text-primary)' }, children: data.length }), ' ', "itens"] })), jsxRuntimeExports.jsx(TableHeader, { columns: columns, gridTemplate: gridTemplate, onSort: onSort ? handleSort : undefined, sortColumn: sortColumn, sortDirection: sortDirection, hasActions: actions.length > 0 }), jsxRuntimeExports.jsx("div", { role: "rowgroup", style: {
|
|
1780
2159
|
maxHeight,
|
|
1781
2160
|
overflowY: 'auto'
|
|
1782
2161
|
}, children: filteredData.map((item, index) => (jsxRuntimeExports.jsx(TableRow, { item: item, index: index, columns: columns, actions: actions, gridTemplate: gridTemplate, isLast: index === filteredData.length - 1, variant: variant, onActionClick: handleActionClick }, item.id || index))) })] }));
|
|
@@ -2184,12 +2563,233 @@ const getTableConfig = (type) => {
|
|
|
2184
2563
|
}
|
|
2185
2564
|
};
|
|
2186
2565
|
|
|
2566
|
+
/**
|
|
2567
|
+
* FormField - Normalized wrapper for form inputs
|
|
2568
|
+
*
|
|
2569
|
+
* Pattern extracted from AdminUserModal.tsx (backoffice/users)
|
|
2570
|
+
* Provides consistent label, error, and helper text styling
|
|
2571
|
+
*/
|
|
2572
|
+
function FormField({ label, required = false, error, helper, disabled = false, children, className = '' }) {
|
|
2573
|
+
return (jsxRuntimeExports.jsxs("div", { className: `mds-form-field ${className}`, style: { opacity: disabled ? 0.6 : 1 }, children: [jsxRuntimeExports.jsxs("label", { style: {
|
|
2574
|
+
display: 'block',
|
|
2575
|
+
marginBottom: '6px',
|
|
2576
|
+
color: 'var(--mds-color-text-primary, var(--text-primary))',
|
|
2577
|
+
fontSize: '0.9rem',
|
|
2578
|
+
fontWeight: 500
|
|
2579
|
+
}, children: [label, required && (jsxRuntimeExports.jsx("span", { style: { color: 'var(--mds-color-error, #ef4444)', marginLeft: '4px' }, children: "*" }))] }), children, error && (jsxRuntimeExports.jsx("span", { style: {
|
|
2580
|
+
color: 'var(--mds-color-error, #ef4444)',
|
|
2581
|
+
fontSize: '0.8rem',
|
|
2582
|
+
marginTop: '4px',
|
|
2583
|
+
display: 'block'
|
|
2584
|
+
}, children: error })), helper && !error && (jsxRuntimeExports.jsx("span", { style: {
|
|
2585
|
+
color: 'var(--mds-color-text-secondary, var(--text-secondary))',
|
|
2586
|
+
fontSize: '0.75rem',
|
|
2587
|
+
marginTop: '4px',
|
|
2588
|
+
display: 'block'
|
|
2589
|
+
}, children: helper }))] }));
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
const gapValues = {
|
|
2593
|
+
sm: '12px',
|
|
2594
|
+
md: '16px',
|
|
2595
|
+
lg: '24px'
|
|
2596
|
+
};
|
|
2597
|
+
/**
|
|
2598
|
+
* FormGrid - Normalized grid layout for form fields
|
|
2599
|
+
*
|
|
2600
|
+
* Pattern extracted from AdminUserModal.tsx (backoffice/users)
|
|
2601
|
+
* Provides consistent 1 or 2 column layouts with proper gap
|
|
2602
|
+
*/
|
|
2603
|
+
function FormGrid({ columns = 1, gap = 'md', children, className = '' }) {
|
|
2604
|
+
return (jsxRuntimeExports.jsx("div", { className: `mds-form-grid ${className}`, style: {
|
|
2605
|
+
display: 'grid',
|
|
2606
|
+
gridTemplateColumns: columns === 2 ? 'repeat(2, 1fr)' : '1fr',
|
|
2607
|
+
gap: gapValues[gap]
|
|
2608
|
+
}, children: children }));
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
/**
|
|
2612
|
+
* FormSection - Normalized section wrapper for grouping form fields
|
|
2613
|
+
*
|
|
2614
|
+
* Pattern extracted from AdminUserModal.tsx (backoffice/users)
|
|
2615
|
+
* Provides consistent section headers and spacing
|
|
2616
|
+
*/
|
|
2617
|
+
function FormSection({ title, description, children, className = '' }) {
|
|
2618
|
+
return (jsxRuntimeExports.jsxs("div", { className: `mds-form-section ${className}`, style: {
|
|
2619
|
+
marginBottom: '24px'
|
|
2620
|
+
}, children: [title && (jsxRuntimeExports.jsx("h4", { style: {
|
|
2621
|
+
margin: '0 0 8px 0',
|
|
2622
|
+
color: 'var(--mds-color-text-primary, var(--text-primary))',
|
|
2623
|
+
fontSize: '1rem',
|
|
2624
|
+
fontWeight: 600,
|
|
2625
|
+
letterSpacing: '-0.02em'
|
|
2626
|
+
}, children: title })), description && (jsxRuntimeExports.jsx("p", { style: {
|
|
2627
|
+
margin: '0 0 16px 0',
|
|
2628
|
+
color: 'var(--mds-color-text-secondary, var(--text-secondary))',
|
|
2629
|
+
fontSize: '0.85rem',
|
|
2630
|
+
lineHeight: 1.5
|
|
2631
|
+
}, children: description })), jsxRuntimeExports.jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '16px' }, children: children })] }));
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
const variantColors = {
|
|
2635
|
+
default: {
|
|
2636
|
+
bg: 'rgba(255, 255, 255, 0.03)',
|
|
2637
|
+
border: 'rgba(255, 255, 255, 0.1)',
|
|
2638
|
+
accent: 'var(--mds-color-text-secondary, #888)'
|
|
2639
|
+
},
|
|
2640
|
+
info: {
|
|
2641
|
+
bg: 'rgba(59, 130, 246, 0.1)',
|
|
2642
|
+
border: 'rgba(59, 130, 246, 0.2)',
|
|
2643
|
+
accent: 'var(--mds-color-info, #3b82f6)'
|
|
2644
|
+
},
|
|
2645
|
+
success: {
|
|
2646
|
+
bg: 'rgba(16, 185, 129, 0.1)',
|
|
2647
|
+
border: 'rgba(16, 185, 129, 0.2)',
|
|
2648
|
+
accent: 'var(--mds-color-success, #10b981)'
|
|
2649
|
+
},
|
|
2650
|
+
warning: {
|
|
2651
|
+
bg: 'rgba(245, 158, 11, 0.1)',
|
|
2652
|
+
border: 'rgba(245, 158, 11, 0.2)',
|
|
2653
|
+
accent: 'var(--mds-color-warning, #f59e0b)'
|
|
2654
|
+
},
|
|
2655
|
+
danger: {
|
|
2656
|
+
bg: 'rgba(239, 68, 68, 0.1)',
|
|
2657
|
+
border: 'rgba(239, 68, 68, 0.2)',
|
|
2658
|
+
accent: 'var(--mds-color-error, #ef4444)'
|
|
2659
|
+
}
|
|
2660
|
+
};
|
|
2661
|
+
/**
|
|
2662
|
+
* InfoBox - Normalized info/alert box for read-only information
|
|
2663
|
+
*
|
|
2664
|
+
* Pattern extracted from AdminUserModal.tsx (backoffice/users)
|
|
2665
|
+
* Provides consistent info boxes for alerts, status displays, and read-only data
|
|
2666
|
+
*
|
|
2667
|
+
* @example
|
|
2668
|
+
* // Alert style (with accent)
|
|
2669
|
+
* <InfoBox variant="info" accent>
|
|
2670
|
+
* An invitation email will be sent...
|
|
2671
|
+
* </InfoBox>
|
|
2672
|
+
*
|
|
2673
|
+
* @example
|
|
2674
|
+
* // Status display (default)
|
|
2675
|
+
* <InfoBox title="User Information">
|
|
2676
|
+
* <InfoRow label="Status" value="Active" />
|
|
2677
|
+
* <InfoRow label="Created" value="Jan 1, 2024" />
|
|
2678
|
+
* </InfoBox>
|
|
2679
|
+
*/
|
|
2680
|
+
function InfoBox({ title, variant = 'default', accent = false, copyable = false, children, className = '' }) {
|
|
2681
|
+
const colors = variantColors[variant];
|
|
2682
|
+
const handleCopy = () => {
|
|
2683
|
+
if (!copyable)
|
|
2684
|
+
return;
|
|
2685
|
+
const text = typeof children === 'string' ? children : '';
|
|
2686
|
+
if (text) {
|
|
2687
|
+
navigator.clipboard.writeText(text);
|
|
2688
|
+
}
|
|
2689
|
+
};
|
|
2690
|
+
return (jsxRuntimeExports.jsxs("div", { className: `mds-info-box ${className}`, style: {
|
|
2691
|
+
padding: '12px 16px',
|
|
2692
|
+
backgroundColor: colors.bg,
|
|
2693
|
+
borderRadius: '8px',
|
|
2694
|
+
border: `1px solid ${colors.border}`,
|
|
2695
|
+
borderLeft: accent ? `4px solid ${colors.accent}` : `1px solid ${colors.border}`,
|
|
2696
|
+
cursor: copyable ? 'pointer' : 'default'
|
|
2697
|
+
}, onClick: copyable ? handleCopy : undefined, title: copyable ? 'Click to copy' : undefined, children: [title && (jsxRuntimeExports.jsx("div", { style: {
|
|
2698
|
+
color: 'var(--mds-color-text-secondary, var(--text-secondary))',
|
|
2699
|
+
fontSize: '0.85rem',
|
|
2700
|
+
marginBottom: '8px',
|
|
2701
|
+
fontWeight: 500
|
|
2702
|
+
}, children: title })), jsxRuntimeExports.jsx("div", { style: {
|
|
2703
|
+
color: 'var(--mds-color-text-primary, var(--text-primary))',
|
|
2704
|
+
fontSize: '0.9rem',
|
|
2705
|
+
lineHeight: 1.5
|
|
2706
|
+
}, children: children })] }));
|
|
2707
|
+
}
|
|
2708
|
+
function InfoRow({ label, value, valueColor }) {
|
|
2709
|
+
return (jsxRuntimeExports.jsxs("div", { style: {
|
|
2710
|
+
display: 'flex',
|
|
2711
|
+
justifyContent: 'space-between',
|
|
2712
|
+
fontSize: '0.85rem',
|
|
2713
|
+
padding: '2px 0'
|
|
2714
|
+
}, children: [jsxRuntimeExports.jsxs("span", { style: { color: 'var(--mds-color-text-secondary, var(--text-secondary))' }, children: [label, ":"] }), jsxRuntimeExports.jsx("span", { style: { color: valueColor || 'var(--mds-color-text-primary, var(--text-primary))' }, children: value })] }));
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
/**
|
|
2718
|
+
* Theme-aware styles generator - Liquid Glass pattern
|
|
2719
|
+
*
|
|
2720
|
+
* Light theme: White semi-transparent overlay to keep background bright
|
|
2721
|
+
* Dark theme: Dark overlay for contrast
|
|
2722
|
+
*/
|
|
2723
|
+
function getStyles(isDark) {
|
|
2724
|
+
return {
|
|
2725
|
+
// Overlay behind the modal
|
|
2726
|
+
overlay: {
|
|
2727
|
+
position: 'fixed',
|
|
2728
|
+
inset: 0,
|
|
2729
|
+
zIndex: 9999,
|
|
2730
|
+
display: 'flex',
|
|
2731
|
+
alignItems: 'center',
|
|
2732
|
+
justifyContent: 'center',
|
|
2733
|
+
padding: 20,
|
|
2734
|
+
// Light theme: white overlay to keep brightness
|
|
2735
|
+
// Dark theme: dark overlay for contrast
|
|
2736
|
+
backgroundColor: isDark ? 'rgba(0, 0, 0, 0.6)' : 'rgba(255, 255, 255, 0.4)',
|
|
2737
|
+
backdropFilter: 'blur(8px)',
|
|
2738
|
+
WebkitBackdropFilter: 'blur(8px)',
|
|
2739
|
+
},
|
|
2740
|
+
// Modal card - Liquid Glass
|
|
2741
|
+
card: {
|
|
2742
|
+
position: 'relative',
|
|
2743
|
+
maxWidth: 640,
|
|
2744
|
+
width: '100%',
|
|
2745
|
+
borderRadius: 24,
|
|
2746
|
+
overflow: 'hidden',
|
|
2747
|
+
// Light theme: Liquid Glass transparency
|
|
2748
|
+
// Dark theme: subtle glass effect
|
|
2749
|
+
background: isDark
|
|
2750
|
+
? 'rgba(255, 255, 255, 0.03)'
|
|
2751
|
+
: 'rgba(255, 255, 255, 0.45)',
|
|
2752
|
+
// Liquid Glass: Strong blur + saturation
|
|
2753
|
+
backdropFilter: 'blur(var(--mds-liquid-blur-xl, 24px)) saturate(var(--mds-liquid-saturate-vibrant, 140%))',
|
|
2754
|
+
WebkitBackdropFilter: 'blur(var(--mds-liquid-blur-xl, 24px)) saturate(var(--mds-liquid-saturate-vibrant, 140%))',
|
|
2755
|
+
// Liquid Glass: Subtle border for edge definition
|
|
2756
|
+
border: isDark
|
|
2757
|
+
? '1px solid rgba(255, 255, 255, 0.08)'
|
|
2758
|
+
: '1px solid rgba(255, 255, 255, 0.9)',
|
|
2759
|
+
// Liquid Glass: Layered shadows + inner glow
|
|
2760
|
+
boxShadow: isDark
|
|
2761
|
+
? 'var(--mds-liquid-shadow-elevated, 0 12px 40px rgba(0, 0, 0, 0.3)), var(--mds-liquid-glow-edge, inset 0 1px 0 rgba(255, 255, 255, 0.1))'
|
|
2762
|
+
: '0 8px 32px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 1)',
|
|
2763
|
+
// Liquid Glass: Smooth transition
|
|
2764
|
+
transition: 'var(--mds-liquid-transition, all 0.25s cubic-bezier(0.25, 0.1, 0.25, 1))',
|
|
2765
|
+
},
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2187
2768
|
function Modal({ open, onClose, closeOnOverlay = true, children, className, style }) {
|
|
2188
2769
|
const [mounted, setMounted] = useState(false);
|
|
2189
2770
|
const [visible, setVisible] = useState(false);
|
|
2190
2771
|
const [renderPortal, setRenderPortal] = useState(false);
|
|
2772
|
+
const [isDarkTheme, setIsDarkTheme] = useState(true);
|
|
2191
2773
|
const containerRef = useRef(null);
|
|
2192
2774
|
useEffect(() => setMounted(true), []);
|
|
2775
|
+
// Detect theme - EXACT same pattern as ProfileCard.tsx
|
|
2776
|
+
useEffect(() => {
|
|
2777
|
+
const checkTheme = () => {
|
|
2778
|
+
const theme = document.documentElement.getAttribute('data-theme');
|
|
2779
|
+
setIsDarkTheme(theme !== 'light');
|
|
2780
|
+
};
|
|
2781
|
+
checkTheme();
|
|
2782
|
+
// Watch for theme changes
|
|
2783
|
+
const observer = new MutationObserver((mutations) => {
|
|
2784
|
+
mutations.forEach((mutation) => {
|
|
2785
|
+
if (mutation.attributeName === 'data-theme') {
|
|
2786
|
+
checkTheme();
|
|
2787
|
+
}
|
|
2788
|
+
});
|
|
2789
|
+
});
|
|
2790
|
+
observer.observe(document.documentElement, { attributes: true });
|
|
2791
|
+
return () => observer.disconnect();
|
|
2792
|
+
}, []);
|
|
2193
2793
|
useEffect(() => {
|
|
2194
2794
|
if (!mounted)
|
|
2195
2795
|
return;
|
|
@@ -2215,30 +2815,178 @@ function Modal({ open, onClose, closeOnOverlay = true, children, className, styl
|
|
|
2215
2815
|
}, [open, onClose]);
|
|
2216
2816
|
if (!mounted || (!renderPortal && !open))
|
|
2217
2817
|
return null;
|
|
2818
|
+
// Get theme-aware styles (same pattern as ProfileCard)
|
|
2819
|
+
const styles = getStyles(isDarkTheme);
|
|
2218
2820
|
const overlayStyle = {
|
|
2219
|
-
|
|
2220
|
-
inset: 0,
|
|
2221
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
2222
|
-
display: 'flex',
|
|
2223
|
-
alignItems: 'center',
|
|
2224
|
-
justifyContent: 'center',
|
|
2225
|
-
zIndex: 1000,
|
|
2226
|
-
padding: '16px',
|
|
2821
|
+
...styles.overlay,
|
|
2227
2822
|
opacity: visible ? 1 : 0,
|
|
2228
|
-
transition: 'opacity 200ms ease'
|
|
2823
|
+
transition: 'opacity 200ms ease',
|
|
2229
2824
|
};
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
transform: visible ? 'scale(1)' : 'scale(0.98)',
|
|
2825
|
+
const cardStyle = {
|
|
2826
|
+
...styles.card,
|
|
2827
|
+
transform: visible ? 'scale(1)' : 'scale(0.96)',
|
|
2234
2828
|
opacity: visible ? 1 : 0,
|
|
2235
|
-
transition: 'opacity 200ms ease, transform 200ms
|
|
2236
|
-
...style
|
|
2829
|
+
transition: 'opacity 200ms ease, transform 200ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
2830
|
+
...style,
|
|
2237
2831
|
};
|
|
2238
|
-
const content = (jsxRuntimeExports.jsx("div", { className: "modal-overlay mds-modal-overlay", style: overlayStyle, onClick: closeOnOverlay ? onClose : undefined, "aria-modal": "true", role: "dialog", children: jsxRuntimeExports.jsx("div", { className: className, style:
|
|
2832
|
+
const content = (jsxRuntimeExports.jsx("div", { className: "modal-overlay mds-modal-overlay", style: overlayStyle, onClick: closeOnOverlay ? onClose : undefined, "aria-modal": "true", role: "dialog", children: jsxRuntimeExports.jsx("div", { className: className, style: cardStyle, onClick: (e) => e.stopPropagation(), ref: (el) => (containerRef.current = el), children: children }) }));
|
|
2239
2833
|
return createPortal(content, document.body);
|
|
2240
2834
|
}
|
|
2241
2835
|
|
|
2836
|
+
const sizeMap$1 = {
|
|
2837
|
+
sm: '400px',
|
|
2838
|
+
md: '480px',
|
|
2839
|
+
lg: '600px',
|
|
2840
|
+
xl: '800px'
|
|
2841
|
+
};
|
|
2842
|
+
/**
|
|
2843
|
+
* FormModal - Normalized template for CRUD modal forms
|
|
2844
|
+
*
|
|
2845
|
+
* Pattern extracted from AdminUserModal.tsx (backoffice/users)
|
|
2846
|
+
* Provides consistent structure for create/edit entity modals
|
|
2847
|
+
*
|
|
2848
|
+
* @example
|
|
2849
|
+
* <FormModal
|
|
2850
|
+
* open={showModal}
|
|
2851
|
+
* onClose={() => setShowModal(false)}
|
|
2852
|
+
* onSubmit={handleSubmit}
|
|
2853
|
+
* title="Edit User"
|
|
2854
|
+
* info="Changes will be saved immediately."
|
|
2855
|
+
* infoVariant="info"
|
|
2856
|
+
* loading={isSaving}
|
|
2857
|
+
* submitText="Save"
|
|
2858
|
+
* >
|
|
2859
|
+
* <FormField label="Name" required error={errors.name}>
|
|
2860
|
+
* <input className="mds-input" value={name} onChange={...} />
|
|
2861
|
+
* </FormField>
|
|
2862
|
+
* </FormModal>
|
|
2863
|
+
*/
|
|
2864
|
+
function FormModal({ open, onClose, onSubmit, title, icon, subtitle, info, infoVariant = 'info', children, submitText = 'Save', cancelText = 'Cancel', loading = false, submitDisabled = false, size = 'md', className = '' }) {
|
|
2865
|
+
const handleSubmit = (e) => {
|
|
2866
|
+
e.preventDefault();
|
|
2867
|
+
onSubmit(e);
|
|
2868
|
+
};
|
|
2869
|
+
return (jsxRuntimeExports.jsxs(Modal, { open: open, onClose: onClose, closeOnOverlay: !loading, className: className, style: {
|
|
2870
|
+
maxWidth: sizeMap$1[size],
|
|
2871
|
+
maxHeight: '90vh',
|
|
2872
|
+
overflowY: 'auto',
|
|
2873
|
+
padding: '24px'
|
|
2874
|
+
}, children: [jsxRuntimeExports.jsxs("div", { style: {
|
|
2875
|
+
display: 'flex',
|
|
2876
|
+
alignItems: 'center',
|
|
2877
|
+
justifyContent: 'space-between',
|
|
2878
|
+
marginBottom: subtitle ? '8px' : '24px'
|
|
2879
|
+
}, children: [jsxRuntimeExports.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [icon && (jsxRuntimeExports.jsx("div", { style: {
|
|
2880
|
+
display: 'flex',
|
|
2881
|
+
alignItems: 'center',
|
|
2882
|
+
justifyContent: 'center',
|
|
2883
|
+
width: 32,
|
|
2884
|
+
height: 32,
|
|
2885
|
+
fontSize: '1.25rem',
|
|
2886
|
+
lineHeight: 0,
|
|
2887
|
+
opacity: 0.5
|
|
2888
|
+
}, children: icon })), jsxRuntimeExports.jsx(Typography, { variant: "h3", color: "primary", style: { margin: 0 }, children: title })] }), jsxRuntimeExports.jsx("button", { type: "button", onClick: onClose, disabled: loading, style: {
|
|
2889
|
+
background: 'none',
|
|
2890
|
+
border: 'none',
|
|
2891
|
+
padding: '8px',
|
|
2892
|
+
cursor: loading ? 'not-allowed' : 'pointer',
|
|
2893
|
+
color: 'var(--mds-color-text-secondary)',
|
|
2894
|
+
opacity: loading ? 0.5 : 1,
|
|
2895
|
+
borderRadius: '6px',
|
|
2896
|
+
display: 'flex',
|
|
2897
|
+
alignItems: 'center',
|
|
2898
|
+
justifyContent: 'center',
|
|
2899
|
+
transition: 'all 0.2s ease'
|
|
2900
|
+
}, onMouseEnter: (e) => {
|
|
2901
|
+
if (!loading)
|
|
2902
|
+
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
|
|
2903
|
+
}, onMouseLeave: (e) => {
|
|
2904
|
+
e.currentTarget.style.backgroundColor = 'transparent';
|
|
2905
|
+
}, "aria-label": "Close modal", children: jsxRuntimeExports.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), subtitle && (jsxRuntimeExports.jsx(Typography, { variant: "body", color: "secondary", style: { marginBottom: '24px', fontSize: '0.9rem' }, children: subtitle })), info && (jsxRuntimeExports.jsx("div", { style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsx(InfoBox, { variant: infoVariant, accent: true, children: info }) })), jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, style: { display: 'flex', flexDirection: 'column', gap: '16px' }, children: [children, jsxRuntimeExports.jsxs("div", { style: {
|
|
2906
|
+
display: 'flex',
|
|
2907
|
+
gap: '12px',
|
|
2908
|
+
justifyContent: 'flex-end',
|
|
2909
|
+
marginTop: '16px',
|
|
2910
|
+
paddingTop: '16px',
|
|
2911
|
+
borderTop: '1px solid rgba(255, 255, 255, 0.1)'
|
|
2912
|
+
}, children: [jsxRuntimeExports.jsx(Button, { variant: "secondary", size: "sm", type: "button", onClick: onClose, disabled: loading, style: { minWidth: '90px' }, children: cancelText }), jsxRuntimeExports.jsx(Button, { variant: "primary", size: "sm", type: "submit", loading: loading, disabled: loading || submitDisabled, style: { minWidth: '110px' }, children: submitText })] })] })] }));
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
const sizeMap = {
|
|
2916
|
+
sm: '400px',
|
|
2917
|
+
md: '480px',
|
|
2918
|
+
lg: '600px',
|
|
2919
|
+
xl: '800px'
|
|
2920
|
+
};
|
|
2921
|
+
/**
|
|
2922
|
+
* DetailModal - Normalized template for read-only detail modals
|
|
2923
|
+
*
|
|
2924
|
+
* Pattern extracted from GeographyDetailsModal, AuditLogDetailModal (backoffice)
|
|
2925
|
+
* Provides consistent structure for viewing entity details
|
|
2926
|
+
*
|
|
2927
|
+
* @example
|
|
2928
|
+
* <DetailModal
|
|
2929
|
+
* open={showDetails}
|
|
2930
|
+
* onClose={() => setShowDetails(false)}
|
|
2931
|
+
* title="User Details"
|
|
2932
|
+
* subtitle="Created on Jan 1, 2024"
|
|
2933
|
+
* action={{
|
|
2934
|
+
* label: 'Edit',
|
|
2935
|
+
* onClick: handleEdit,
|
|
2936
|
+
* variant: 'primary'
|
|
2937
|
+
* }}
|
|
2938
|
+
* >
|
|
2939
|
+
* <InfoBox title="Basic Information">
|
|
2940
|
+
* <InfoRow label="Name" value={user.name} />
|
|
2941
|
+
* <InfoRow label="Email" value={user.email} />
|
|
2942
|
+
* </InfoBox>
|
|
2943
|
+
* </DetailModal>
|
|
2944
|
+
*/
|
|
2945
|
+
function DetailModal({ open, onClose, title, icon, subtitle, children, closeText = 'Close', action, size = 'md', className = '' }) {
|
|
2946
|
+
return (jsxRuntimeExports.jsxs(Modal, { open: open, onClose: onClose, closeOnOverlay: true, className: className, style: {
|
|
2947
|
+
maxWidth: sizeMap[size],
|
|
2948
|
+
maxHeight: '90vh',
|
|
2949
|
+
overflowY: 'auto',
|
|
2950
|
+
padding: '24px'
|
|
2951
|
+
}, children: [jsxRuntimeExports.jsxs("div", { style: {
|
|
2952
|
+
display: 'flex',
|
|
2953
|
+
alignItems: 'center',
|
|
2954
|
+
justifyContent: 'space-between',
|
|
2955
|
+
marginBottom: subtitle ? '8px' : '24px'
|
|
2956
|
+
}, children: [jsxRuntimeExports.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [icon && (jsxRuntimeExports.jsx("div", { style: {
|
|
2957
|
+
display: 'flex',
|
|
2958
|
+
alignItems: 'center',
|
|
2959
|
+
justifyContent: 'center',
|
|
2960
|
+
width: 32,
|
|
2961
|
+
height: 32,
|
|
2962
|
+
fontSize: '1.25rem',
|
|
2963
|
+
lineHeight: 0,
|
|
2964
|
+
opacity: 0.5
|
|
2965
|
+
}, children: icon })), jsxRuntimeExports.jsx(Typography, { variant: "h3", color: "primary", style: { margin: 0 }, children: title })] }), jsxRuntimeExports.jsx("button", { type: "button", onClick: onClose, style: {
|
|
2966
|
+
background: 'none',
|
|
2967
|
+
border: 'none',
|
|
2968
|
+
padding: '8px',
|
|
2969
|
+
cursor: 'pointer',
|
|
2970
|
+
color: 'var(--mds-color-text-secondary)',
|
|
2971
|
+
borderRadius: '6px',
|
|
2972
|
+
display: 'flex',
|
|
2973
|
+
alignItems: 'center',
|
|
2974
|
+
justifyContent: 'center',
|
|
2975
|
+
transition: 'all 0.2s ease'
|
|
2976
|
+
}, onMouseEnter: (e) => {
|
|
2977
|
+
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
|
|
2978
|
+
}, onMouseLeave: (e) => {
|
|
2979
|
+
e.currentTarget.style.backgroundColor = 'transparent';
|
|
2980
|
+
}, "aria-label": "Close modal", children: jsxRuntimeExports.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), subtitle && (jsxRuntimeExports.jsx(Typography, { variant: "body", color: "secondary", style: { marginBottom: '24px', fontSize: '0.9rem' }, children: subtitle })), jsxRuntimeExports.jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '16px' }, children: children }), jsxRuntimeExports.jsxs("div", { style: {
|
|
2981
|
+
display: 'flex',
|
|
2982
|
+
gap: '12px',
|
|
2983
|
+
justifyContent: 'flex-end',
|
|
2984
|
+
marginTop: '24px',
|
|
2985
|
+
paddingTop: '16px',
|
|
2986
|
+
borderTop: '1px solid rgba(255, 255, 255, 0.1)'
|
|
2987
|
+
}, children: [jsxRuntimeExports.jsx(Button, { variant: "secondary", size: "sm", onClick: onClose, children: closeText }), action && (jsxRuntimeExports.jsx(Button, { variant: action.variant || 'primary', size: "sm", onClick: action.onClick, disabled: action.disabled, children: action.label }))] })] }));
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2242
2990
|
function ModalHeader({ title, icon, onClose, closeAriaLabel = 'Fechar', align = 'center' }) {
|
|
2243
2991
|
const CloseIcon = (jsxRuntimeExports.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: jsxRuntimeExports.jsx("path", { d: "M18.3 5.71a1 1 0 00-1.41 0L12 10.59 7.11 5.7A1 1 0 105.7 7.11L10.59 12l-4.9 4.89a1 1 0 101.42 1.42L12 13.41l4.89 4.9a1 1 0 001.42-1.42L13.41 12l4.9-4.89a1 1 0 000-1.4z" }) }));
|
|
2244
2992
|
if (align === 'center') {
|
|
@@ -2253,7 +3001,8 @@ function ModalHeader({ title, icon, onClose, closeAriaLabel = 'Fechar', align =
|
|
|
2253
3001
|
alignItems: 'center',
|
|
2254
3002
|
justifyContent: 'center',
|
|
2255
3003
|
fontSize: '1.25rem',
|
|
2256
|
-
lineHeight: 0
|
|
3004
|
+
lineHeight: 0,
|
|
3005
|
+
opacity: 0.5
|
|
2257
3006
|
};
|
|
2258
3007
|
const closeBox = {
|
|
2259
3008
|
position: 'absolute',
|
|
@@ -2285,7 +3034,7 @@ function ModalHeader({ title, icon, onClose, closeAriaLabel = 'Fechar', align =
|
|
|
2285
3034
|
padding: '16px 24px',
|
|
2286
3035
|
marginBottom: 16,
|
|
2287
3036
|
borderBottom: '1px solid var(--border-color)'
|
|
2288
|
-
}, children: [icon && (jsxRuntimeExports.jsx("div", { "aria-hidden": true, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 32, height: 32, fontSize: '1.25rem', lineHeight: 0 }, children: icon })), jsxRuntimeExports.jsx("div", { style: { margin: 0, fontSize: '1.125rem', fontWeight: 600, flex: 1 }, children: typeof title === 'string' ? (jsxRuntimeExports.jsx("h3", { style: { margin: 0 }, children: title })) : (title) }), onClose && (jsxRuntimeExports.jsx("button", { type: "button", "aria-label": closeAriaLabel, onClick: onClose, style: { marginLeft: 'auto', background: 'transparent', border: 'none', width: 32, height: 32, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', lineHeight: 0 }, children: CloseIcon }))] }));
|
|
3037
|
+
}, children: [icon && (jsxRuntimeExports.jsx("div", { "aria-hidden": true, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 32, height: 32, fontSize: '1.25rem', lineHeight: 0, opacity: 0.5 }, children: icon })), jsxRuntimeExports.jsx("div", { style: { margin: 0, fontSize: '1.125rem', fontWeight: 600, flex: 1 }, children: typeof title === 'string' ? (jsxRuntimeExports.jsx("h3", { style: { margin: 0 }, children: title })) : (title) }), onClose && (jsxRuntimeExports.jsx("button", { type: "button", "aria-label": closeAriaLabel, onClick: onClose, style: { marginLeft: 'auto', background: 'transparent', border: 'none', width: 32, height: 32, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', lineHeight: 0 }, children: CloseIcon }))] }));
|
|
2289
3038
|
}
|
|
2290
3039
|
|
|
2291
3040
|
function ModalBody({ children, style, className }) {
|
|
@@ -2311,5 +3060,5 @@ function ConfirmDialog({ open, onClose, title, description, confirmText = 'Confi
|
|
|
2311
3060
|
return (jsxRuntimeExports.jsx(Modal, { open: open, onClose: onClose, closeOnOverlay: !disableOverlayClose, children: jsxRuntimeExports.jsxs("div", { className: "mds-modal-card", style: { maxWidth: 480, width: '100%' }, children: [jsxRuntimeExports.jsx(ModalHeader, { title: title, icon: icon ?? toneIcon[tone], onClose: onClose, align: "center" }), description && (jsxRuntimeExports.jsx("div", { style: { padding: '0 24px 16px 24px' }, children: description })), jsxRuntimeExports.jsxs("div", { style: { display: 'flex', gap: 12, justifyContent: 'flex-end', borderTop: '1px solid var(--border-color)', padding: '16px 24px', marginTop: 8 }, children: [jsxRuntimeExports.jsx("button", { type: "button", onClick: onClose, className: "mds-button mds-button--secondary", children: cancelText }), jsxRuntimeExports.jsx("button", { type: "button", onClick: onConfirm, disabled: loading, className: "mds-button mds-button--primary", children: loading ? 'Processando...' : confirmText })] })] }) }));
|
|
2312
3061
|
}
|
|
2313
3062
|
|
|
2314
|
-
export { ActionIcons, BrandLogo, Button, CellRenderers, ConfirmDialog, DataTable, GlassCard, Modal, ModalBody, ModalFooter, ModalHeader, Select, TableHeader, TableRow, ThemeToggle, Typography, auditLogTableConfig, citiesTableConfig, cn, countriesTableConfig, getTableConfig, parametersTableConfig, regionsTableConfig, statesTableConfig };
|
|
3063
|
+
export { ActionIcons, BrandLogo, Button, CellRenderers, ConfirmDialog, DataTable, DetailModal, FormField, FormGrid, FormModal, FormSection, GlassCard, InfoBox, InfoRow, Modal, ModalBody, ModalFooter, ModalHeader, ProfileCard, Select, TableHeader, TableRow, ThemeToggle, Typography, auditLogTableConfig, citiesTableConfig, cn, countriesTableConfig, getTableConfig, parametersTableConfig, regionsTableConfig, statesTableConfig };
|
|
2315
3064
|
//# sourceMappingURL=index.esm.js.map
|