@metropolle/design-system 1.2025.1-2.5.1903 → 1.2026.0-1.1.1728
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/components.css +414 -126
- package/dist/css/liquid-glass.css +468 -0
- package/dist/react/components/react/GlassCard/GlassCard.d.ts +46 -6
- package/dist/react/components/react/GlassCard/GlassCard.d.ts.map +1 -1
- package/dist/react/components/react/Modal/Modal.d.ts.map +1 -1
- 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 +1 -1
- package/dist/react/components/react/index.d.ts.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.esm.js +352 -42
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/index.js +351 -41
- package/dist/react/index.js.map +1 -1
- package/package.json +4 -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,35 @@ 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, 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
|
+
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-liquid-glass', `mds-liquid-glass--${intensity}`, !enableHover && 'mds-liquid-glass--no-hover', className), style: style, ...props, children: children }));
|
|
1396
|
+
}
|
|
1397
|
+
// =====================
|
|
1398
|
+
// GLASS MODE (legacy)
|
|
1399
|
+
// =====================
|
|
1377
1400
|
// Default opacities baseadas no design existente
|
|
1378
|
-
const defaultOpacity =
|
|
1401
|
+
const defaultOpacity = resolvedTheme === 'light' ? 0.15 : 0.8;
|
|
1379
1402
|
const finalOpacity = opacity ?? defaultOpacity;
|
|
1380
1403
|
// Use CSS classes for base styles to avoid hydration mismatches
|
|
1381
1404
|
const baseStyles = {
|
|
@@ -1383,12 +1406,16 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1383
1406
|
};
|
|
1384
1407
|
// Only apply custom styles for non-default values
|
|
1385
1408
|
const customStyles = {};
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1409
|
+
// Support legacy blur prop or convert from intensity
|
|
1410
|
+
const resolvedBlur = blur ?? (intensity ? {
|
|
1411
|
+
xs: 2, sm: 4, md: 6, lg: 8, xl: 12
|
|
1412
|
+
}[intensity] : 20);
|
|
1413
|
+
if (resolvedBlur !== 20) {
|
|
1414
|
+
customStyles.backdropFilter = `blur(${resolvedBlur}px)`;
|
|
1415
|
+
customStyles.WebkitBackdropFilter = `blur(${resolvedBlur}px)`;
|
|
1389
1416
|
}
|
|
1390
1417
|
if (opacity !== undefined) {
|
|
1391
|
-
customStyles.background =
|
|
1418
|
+
customStyles.background = resolvedTheme === 'light'
|
|
1392
1419
|
? `rgba(255, 255, 255, ${finalOpacity})`
|
|
1393
1420
|
: `rgba(60, 60, 60, ${finalOpacity})`;
|
|
1394
1421
|
}
|
|
@@ -1403,7 +1430,7 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1403
1430
|
borderColor: 'rgba(255, 255, 255, 0.2)',
|
|
1404
1431
|
background: opacity !== undefined ? `rgba(70, 70, 70, ${finalOpacity})` : undefined,
|
|
1405
1432
|
}
|
|
1406
|
-
}[
|
|
1433
|
+
}[resolvedTheme] : {};
|
|
1407
1434
|
const handleMouseEnter = (e) => {
|
|
1408
1435
|
if (!enableHover)
|
|
1409
1436
|
return;
|
|
@@ -1421,7 +1448,7 @@ const GlassCard = forwardRef(({ variant = 'light', blur = 20, opacity, children,
|
|
|
1421
1448
|
});
|
|
1422
1449
|
props.onMouseLeave?.(e);
|
|
1423
1450
|
};
|
|
1424
|
-
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-glass-card', `mds-glass-card--${
|
|
1451
|
+
return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('mds-glass-card', `mds-glass-card--${resolvedTheme}`, !enableHover && 'mds-glass-card--no-hover', className), style: {
|
|
1425
1452
|
...baseStyles,
|
|
1426
1453
|
...customStyles,
|
|
1427
1454
|
...style
|
|
@@ -1493,22 +1520,241 @@ const LoadingSpinner = () => (jsxRuntimeExports.jsxs("svg", { className: "mds-sp
|
|
|
1493
1520
|
/**
|
|
1494
1521
|
* Select Component (Design System)
|
|
1495
1522
|
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1523
|
+
* Custom dropdown select that renders consistently across all browsers.
|
|
1524
|
+
* Unlike native <select>, this component renders the dropdown via JavaScript,
|
|
1525
|
+
* ensuring proper theming support on Edge/Chrome Windows.
|
|
1526
|
+
*
|
|
1527
|
+
* @example
|
|
1528
|
+
* ```tsx
|
|
1529
|
+
* <Select
|
|
1530
|
+
* options={[
|
|
1531
|
+
* { label: 'Option 1', value: '1' },
|
|
1532
|
+
* { label: 'Option 2', value: '2' },
|
|
1533
|
+
* ]}
|
|
1534
|
+
* value={selectedValue}
|
|
1535
|
+
* onChange={setSelectedValue}
|
|
1536
|
+
* placeholder="Select an option..."
|
|
1537
|
+
* />
|
|
1538
|
+
* ```
|
|
1500
1539
|
*/
|
|
1501
|
-
const Select = forwardRef(({ options,
|
|
1502
|
-
const
|
|
1503
|
-
const
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1540
|
+
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) => {
|
|
1541
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1542
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
1543
|
+
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
1544
|
+
const [mounted, setMounted] = useState(false);
|
|
1545
|
+
const triggerRef = useRef(null);
|
|
1546
|
+
const dropdownRef = useRef(null);
|
|
1547
|
+
const searchInputRef = useRef(null);
|
|
1548
|
+
const listRef = useRef(null);
|
|
1549
|
+
// Combine refs
|
|
1550
|
+
const combinedRef = (el) => {
|
|
1551
|
+
triggerRef.current = el;
|
|
1552
|
+
if (typeof ref === 'function') {
|
|
1553
|
+
ref(el);
|
|
1554
|
+
}
|
|
1555
|
+
else if (ref) {
|
|
1556
|
+
ref.current = el;
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
// Client-side only
|
|
1560
|
+
useEffect(() => {
|
|
1561
|
+
setMounted(true);
|
|
1562
|
+
}, []);
|
|
1563
|
+
// Filter options based on search
|
|
1564
|
+
const filteredOptions = useMemo(() => {
|
|
1565
|
+
if (!searchTerm)
|
|
1566
|
+
return options;
|
|
1567
|
+
const term = searchTerm.toLowerCase();
|
|
1568
|
+
return options.filter(opt => {
|
|
1569
|
+
const label = typeof opt.label === 'string' ? opt.label : String(opt.value);
|
|
1570
|
+
return label.toLowerCase().includes(term);
|
|
1571
|
+
});
|
|
1572
|
+
}, [options, searchTerm]);
|
|
1573
|
+
// Get selected option label
|
|
1574
|
+
const selectedOption = useMemo(() => {
|
|
1575
|
+
return options.find(opt => opt.value === value);
|
|
1576
|
+
}, [options, value]);
|
|
1577
|
+
// Handle dropdown positioning
|
|
1578
|
+
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 });
|
|
1579
|
+
const updateDropdownPosition = useCallback(() => {
|
|
1580
|
+
if (!triggerRef.current)
|
|
1581
|
+
return;
|
|
1582
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
1583
|
+
const viewportHeight = window.innerHeight;
|
|
1584
|
+
const spaceBelow = viewportHeight - rect.bottom;
|
|
1585
|
+
const spaceAbove = rect.top;
|
|
1586
|
+
// Determine if dropdown should open above or below
|
|
1587
|
+
const dropdownHeight = Math.min(maxHeight, filteredOptions.length * 40 + (searchable ? 48 : 0));
|
|
1588
|
+
const openAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;
|
|
1589
|
+
setDropdownPosition({
|
|
1590
|
+
top: openAbove ? rect.top - dropdownHeight : rect.bottom + 4,
|
|
1591
|
+
left: rect.left,
|
|
1592
|
+
width: rect.width,
|
|
1593
|
+
});
|
|
1594
|
+
}, [maxHeight, filteredOptions.length, searchable]);
|
|
1595
|
+
// Open dropdown
|
|
1596
|
+
const openDropdown = useCallback(() => {
|
|
1597
|
+
if (disabled || loading)
|
|
1598
|
+
return;
|
|
1599
|
+
updateDropdownPosition();
|
|
1600
|
+
setIsOpen(true);
|
|
1601
|
+
setSearchTerm('');
|
|
1602
|
+
setHighlightedIndex(value ? filteredOptions.findIndex(opt => opt.value === value) : 0);
|
|
1603
|
+
}, [disabled, loading, updateDropdownPosition, value, filteredOptions]);
|
|
1604
|
+
// Close dropdown
|
|
1605
|
+
const closeDropdown = useCallback(() => {
|
|
1606
|
+
setIsOpen(false);
|
|
1607
|
+
setSearchTerm('');
|
|
1608
|
+
setHighlightedIndex(-1);
|
|
1609
|
+
triggerRef.current?.focus();
|
|
1610
|
+
}, []);
|
|
1611
|
+
// Handle option select
|
|
1612
|
+
const handleSelect = useCallback((optionValue) => {
|
|
1613
|
+
// Safety check: ensure we're passing a string, not an object
|
|
1614
|
+
const safeValue = typeof optionValue === 'string' ? optionValue : String(optionValue);
|
|
1615
|
+
onChange?.(safeValue);
|
|
1616
|
+
closeDropdown();
|
|
1617
|
+
}, [onChange, closeDropdown]);
|
|
1618
|
+
// Keyboard navigation
|
|
1619
|
+
const handleKeyDown = useCallback((e) => {
|
|
1620
|
+
if (disabled || loading)
|
|
1621
|
+
return;
|
|
1622
|
+
switch (e.key) {
|
|
1623
|
+
case 'Enter':
|
|
1624
|
+
case ' ':
|
|
1625
|
+
e.preventDefault();
|
|
1626
|
+
if (isOpen && highlightedIndex >= 0 && filteredOptions[highlightedIndex]) {
|
|
1627
|
+
const opt = filteredOptions[highlightedIndex];
|
|
1628
|
+
if (!opt.disabled) {
|
|
1629
|
+
handleSelect(opt.value);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
else if (!isOpen) {
|
|
1633
|
+
openDropdown();
|
|
1634
|
+
}
|
|
1635
|
+
break;
|
|
1636
|
+
case 'ArrowDown':
|
|
1637
|
+
e.preventDefault();
|
|
1638
|
+
if (!isOpen) {
|
|
1639
|
+
openDropdown();
|
|
1640
|
+
}
|
|
1641
|
+
else {
|
|
1642
|
+
setHighlightedIndex(prev => {
|
|
1643
|
+
const next = prev + 1;
|
|
1644
|
+
return next >= filteredOptions.length ? 0 : next;
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
break;
|
|
1648
|
+
case 'ArrowUp':
|
|
1649
|
+
e.preventDefault();
|
|
1650
|
+
if (isOpen) {
|
|
1651
|
+
setHighlightedIndex(prev => {
|
|
1652
|
+
const next = prev - 1;
|
|
1653
|
+
return next < 0 ? filteredOptions.length - 1 : next;
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
break;
|
|
1657
|
+
case 'Escape':
|
|
1658
|
+
e.preventDefault();
|
|
1659
|
+
closeDropdown();
|
|
1660
|
+
break;
|
|
1661
|
+
case 'Tab':
|
|
1662
|
+
if (isOpen) {
|
|
1663
|
+
closeDropdown();
|
|
1664
|
+
}
|
|
1665
|
+
break;
|
|
1666
|
+
case 'Home':
|
|
1667
|
+
if (isOpen) {
|
|
1668
|
+
e.preventDefault();
|
|
1669
|
+
setHighlightedIndex(0);
|
|
1670
|
+
}
|
|
1671
|
+
break;
|
|
1672
|
+
case 'End':
|
|
1673
|
+
if (isOpen) {
|
|
1674
|
+
e.preventDefault();
|
|
1675
|
+
setHighlightedIndex(filteredOptions.length - 1);
|
|
1676
|
+
}
|
|
1677
|
+
break;
|
|
1678
|
+
}
|
|
1679
|
+
}, [disabled, loading, isOpen, highlightedIndex, filteredOptions, handleSelect, openDropdown, closeDropdown]);
|
|
1680
|
+
// Click outside to close
|
|
1681
|
+
useEffect(() => {
|
|
1682
|
+
if (!isOpen)
|
|
1683
|
+
return;
|
|
1684
|
+
const handleClickOutside = (e) => {
|
|
1685
|
+
if (triggerRef.current?.contains(e.target) ||
|
|
1686
|
+
dropdownRef.current?.contains(e.target)) {
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
closeDropdown();
|
|
1690
|
+
};
|
|
1691
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
1692
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
1693
|
+
}, [isOpen, closeDropdown]);
|
|
1694
|
+
// Update position on scroll/resize
|
|
1695
|
+
useEffect(() => {
|
|
1696
|
+
if (!isOpen)
|
|
1697
|
+
return;
|
|
1698
|
+
const handleUpdate = () => updateDropdownPosition();
|
|
1699
|
+
window.addEventListener('scroll', handleUpdate, true);
|
|
1700
|
+
window.addEventListener('resize', handleUpdate);
|
|
1701
|
+
return () => {
|
|
1702
|
+
window.removeEventListener('scroll', handleUpdate, true);
|
|
1703
|
+
window.removeEventListener('resize', handleUpdate);
|
|
1704
|
+
};
|
|
1705
|
+
}, [isOpen, updateDropdownPosition]);
|
|
1706
|
+
// Focus search input when dropdown opens
|
|
1707
|
+
useEffect(() => {
|
|
1708
|
+
if (isOpen && searchable && searchInputRef.current) {
|
|
1709
|
+
searchInputRef.current.focus();
|
|
1710
|
+
}
|
|
1711
|
+
}, [isOpen, searchable]);
|
|
1712
|
+
// Scroll highlighted option into view
|
|
1713
|
+
useEffect(() => {
|
|
1714
|
+
if (!isOpen || highlightedIndex < 0 || !listRef.current)
|
|
1715
|
+
return;
|
|
1716
|
+
const highlighted = listRef.current.children[highlightedIndex];
|
|
1717
|
+
if (highlighted) {
|
|
1718
|
+
highlighted.scrollIntoView({ block: 'nearest' });
|
|
1719
|
+
}
|
|
1720
|
+
}, [isOpen, highlightedIndex]);
|
|
1721
|
+
// Size classes
|
|
1722
|
+
const sizeClasses = {
|
|
1723
|
+
sm: 'mds-select--sm',
|
|
1724
|
+
md: 'mds-select--md',
|
|
1725
|
+
lg: 'mds-select--lg',
|
|
1726
|
+
};
|
|
1727
|
+
// Variant classes
|
|
1728
|
+
const variantClasses = {
|
|
1729
|
+
base: 'mds-select--base',
|
|
1730
|
+
themed: 'mds-select--themed',
|
|
1731
|
+
dashboard: 'mds-select--themed',
|
|
1732
|
+
};
|
|
1733
|
+
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);
|
|
1734
|
+
const dropdownClasses = cn('mds-select-dropdown', variantClasses[variant], dropdownClassName);
|
|
1735
|
+
// Hidden input for form submission
|
|
1736
|
+
const hiddenInput = name ? (jsxRuntimeExports.jsx("input", { type: "hidden", name: name, value: value || '' })) : null;
|
|
1737
|
+
// Dropdown portal content
|
|
1738
|
+
const dropdownContent = isOpen && mounted ? createPortal(jsxRuntimeExports.jsxs("div", { ref: dropdownRef, className: dropdownClasses, style: {
|
|
1739
|
+
position: 'fixed',
|
|
1740
|
+
top: dropdownPosition.top,
|
|
1741
|
+
left: dropdownPosition.left,
|
|
1742
|
+
width: dropdownPosition.width,
|
|
1743
|
+
maxHeight,
|
|
1744
|
+
zIndex,
|
|
1745
|
+
}, 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) => {
|
|
1746
|
+
setSearchTerm(e.target.value);
|
|
1747
|
+
setHighlightedIndex(0);
|
|
1748
|
+
}, 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: () => {
|
|
1749
|
+
if (!option.disabled) {
|
|
1750
|
+
handleSelect(option.value);
|
|
1751
|
+
}
|
|
1752
|
+
}, onMouseEnter: () => {
|
|
1753
|
+
if (!option.disabled) {
|
|
1754
|
+
setHighlightedIndex(index);
|
|
1755
|
+
}
|
|
1756
|
+
}, 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;
|
|
1757
|
+
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
1758
|
});
|
|
1513
1759
|
Select.displayName = 'Select';
|
|
1514
1760
|
|
|
@@ -2184,12 +2430,82 @@ const getTableConfig = (type) => {
|
|
|
2184
2430
|
}
|
|
2185
2431
|
};
|
|
2186
2432
|
|
|
2433
|
+
/**
|
|
2434
|
+
* Theme-aware styles generator - Liquid Glass pattern
|
|
2435
|
+
*
|
|
2436
|
+
* Light theme: White semi-transparent overlay to keep background bright
|
|
2437
|
+
* Dark theme: Dark overlay for contrast
|
|
2438
|
+
*/
|
|
2439
|
+
function getStyles(isDark) {
|
|
2440
|
+
return {
|
|
2441
|
+
// Overlay behind the modal
|
|
2442
|
+
overlay: {
|
|
2443
|
+
position: 'fixed',
|
|
2444
|
+
inset: 0,
|
|
2445
|
+
zIndex: 9999,
|
|
2446
|
+
display: 'flex',
|
|
2447
|
+
alignItems: 'center',
|
|
2448
|
+
justifyContent: 'center',
|
|
2449
|
+
padding: 20,
|
|
2450
|
+
// Light theme: white overlay to keep brightness
|
|
2451
|
+
// Dark theme: dark overlay for contrast
|
|
2452
|
+
backgroundColor: isDark ? 'rgba(0, 0, 0, 0.6)' : 'rgba(255, 255, 255, 0.4)',
|
|
2453
|
+
backdropFilter: 'blur(8px)',
|
|
2454
|
+
WebkitBackdropFilter: 'blur(8px)',
|
|
2455
|
+
},
|
|
2456
|
+
// Modal card - Liquid Glass
|
|
2457
|
+
card: {
|
|
2458
|
+
position: 'relative',
|
|
2459
|
+
maxWidth: 640,
|
|
2460
|
+
width: '100%',
|
|
2461
|
+
borderRadius: 24,
|
|
2462
|
+
overflow: 'hidden',
|
|
2463
|
+
// Light theme: Liquid Glass transparency
|
|
2464
|
+
// Dark theme: subtle glass effect
|
|
2465
|
+
background: isDark
|
|
2466
|
+
? 'rgba(255, 255, 255, 0.03)'
|
|
2467
|
+
: 'rgba(255, 255, 255, 0.55)',
|
|
2468
|
+
// Liquid Glass: Strong blur + saturation
|
|
2469
|
+
backdropFilter: 'blur(var(--mds-liquid-blur-xl, 24px)) saturate(var(--mds-liquid-saturate-vibrant, 140%))',
|
|
2470
|
+
WebkitBackdropFilter: 'blur(var(--mds-liquid-blur-xl, 24px)) saturate(var(--mds-liquid-saturate-vibrant, 140%))',
|
|
2471
|
+
// Liquid Glass: Subtle border for edge definition
|
|
2472
|
+
border: isDark
|
|
2473
|
+
? '1px solid rgba(255, 255, 255, 0.08)'
|
|
2474
|
+
: '1px solid rgba(255, 255, 255, 0.9)',
|
|
2475
|
+
// Liquid Glass: Layered shadows + inner glow
|
|
2476
|
+
boxShadow: isDark
|
|
2477
|
+
? '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))'
|
|
2478
|
+
: '0 8px 32px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 1)',
|
|
2479
|
+
// Liquid Glass: Smooth transition
|
|
2480
|
+
transition: 'var(--mds-liquid-transition, all 0.25s cubic-bezier(0.25, 0.1, 0.25, 1))',
|
|
2481
|
+
},
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2187
2484
|
function Modal({ open, onClose, closeOnOverlay = true, children, className, style }) {
|
|
2188
2485
|
const [mounted, setMounted] = useState(false);
|
|
2189
2486
|
const [visible, setVisible] = useState(false);
|
|
2190
2487
|
const [renderPortal, setRenderPortal] = useState(false);
|
|
2488
|
+
const [isDarkTheme, setIsDarkTheme] = useState(true);
|
|
2191
2489
|
const containerRef = useRef(null);
|
|
2192
2490
|
useEffect(() => setMounted(true), []);
|
|
2491
|
+
// Detect theme - EXACT same pattern as ProfileCard.tsx
|
|
2492
|
+
useEffect(() => {
|
|
2493
|
+
const checkTheme = () => {
|
|
2494
|
+
const theme = document.documentElement.getAttribute('data-theme');
|
|
2495
|
+
setIsDarkTheme(theme !== 'light');
|
|
2496
|
+
};
|
|
2497
|
+
checkTheme();
|
|
2498
|
+
// Watch for theme changes
|
|
2499
|
+
const observer = new MutationObserver((mutations) => {
|
|
2500
|
+
mutations.forEach((mutation) => {
|
|
2501
|
+
if (mutation.attributeName === 'data-theme') {
|
|
2502
|
+
checkTheme();
|
|
2503
|
+
}
|
|
2504
|
+
});
|
|
2505
|
+
});
|
|
2506
|
+
observer.observe(document.documentElement, { attributes: true });
|
|
2507
|
+
return () => observer.disconnect();
|
|
2508
|
+
}, []);
|
|
2193
2509
|
useEffect(() => {
|
|
2194
2510
|
if (!mounted)
|
|
2195
2511
|
return;
|
|
@@ -2215,27 +2531,21 @@ function Modal({ open, onClose, closeOnOverlay = true, children, className, styl
|
|
|
2215
2531
|
}, [open, onClose]);
|
|
2216
2532
|
if (!mounted || (!renderPortal && !open))
|
|
2217
2533
|
return null;
|
|
2534
|
+
// Get theme-aware styles (same pattern as ProfileCard)
|
|
2535
|
+
const styles = getStyles(isDarkTheme);
|
|
2218
2536
|
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',
|
|
2537
|
+
...styles.overlay,
|
|
2227
2538
|
opacity: visible ? 1 : 0,
|
|
2228
|
-
transition: 'opacity 200ms ease'
|
|
2539
|
+
transition: 'opacity 200ms ease',
|
|
2229
2540
|
};
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
transform: visible ? 'scale(1)' : 'scale(0.98)',
|
|
2541
|
+
const cardStyle = {
|
|
2542
|
+
...styles.card,
|
|
2543
|
+
transform: visible ? 'scale(1)' : 'scale(0.96)',
|
|
2234
2544
|
opacity: visible ? 1 : 0,
|
|
2235
|
-
transition: 'opacity 200ms ease, transform 200ms
|
|
2236
|
-
...style
|
|
2545
|
+
transition: 'opacity 200ms ease, transform 200ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
2546
|
+
...style,
|
|
2237
2547
|
};
|
|
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:
|
|
2548
|
+
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
2549
|
return createPortal(content, document.body);
|
|
2240
2550
|
}
|
|
2241
2551
|
|