@metropolle/design-system 1.2025.1-2.29.949 → 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 +338 -123
- 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 +315 -32
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/index.js +314 -31
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
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: {}};
|
|
@@ -1520,22 +1520,241 @@ const LoadingSpinner = () => (jsxRuntimeExports.jsxs("svg", { className: "mds-sp
|
|
|
1520
1520
|
/**
|
|
1521
1521
|
* Select Component (Design System)
|
|
1522
1522
|
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1526
|
-
*
|
|
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
|
+
* ```
|
|
1527
1539
|
*/
|
|
1528
|
-
const Select = forwardRef(({ options,
|
|
1529
|
-
const
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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] }));
|
|
1539
1758
|
});
|
|
1540
1759
|
Select.displayName = 'Select';
|
|
1541
1760
|
|
|
@@ -2211,12 +2430,82 @@ const getTableConfig = (type) => {
|
|
|
2211
2430
|
}
|
|
2212
2431
|
};
|
|
2213
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
|
+
}
|
|
2214
2484
|
function Modal({ open, onClose, closeOnOverlay = true, children, className, style }) {
|
|
2215
2485
|
const [mounted, setMounted] = useState(false);
|
|
2216
2486
|
const [visible, setVisible] = useState(false);
|
|
2217
2487
|
const [renderPortal, setRenderPortal] = useState(false);
|
|
2488
|
+
const [isDarkTheme, setIsDarkTheme] = useState(true);
|
|
2218
2489
|
const containerRef = useRef(null);
|
|
2219
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
|
+
}, []);
|
|
2220
2509
|
useEffect(() => {
|
|
2221
2510
|
if (!mounted)
|
|
2222
2511
|
return;
|
|
@@ -2242,27 +2531,21 @@ function Modal({ open, onClose, closeOnOverlay = true, children, className, styl
|
|
|
2242
2531
|
}, [open, onClose]);
|
|
2243
2532
|
if (!mounted || (!renderPortal && !open))
|
|
2244
2533
|
return null;
|
|
2534
|
+
// Get theme-aware styles (same pattern as ProfileCard)
|
|
2535
|
+
const styles = getStyles(isDarkTheme);
|
|
2245
2536
|
const overlayStyle = {
|
|
2246
|
-
|
|
2247
|
-
inset: 0,
|
|
2248
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
2249
|
-
display: 'flex',
|
|
2250
|
-
alignItems: 'center',
|
|
2251
|
-
justifyContent: 'center',
|
|
2252
|
-
zIndex: 1000,
|
|
2253
|
-
padding: '16px',
|
|
2537
|
+
...styles.overlay,
|
|
2254
2538
|
opacity: visible ? 1 : 0,
|
|
2255
|
-
transition: 'opacity 200ms ease'
|
|
2539
|
+
transition: 'opacity 200ms ease',
|
|
2256
2540
|
};
|
|
2257
|
-
const
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
transform: visible ? 'scale(1)' : 'scale(0.98)',
|
|
2541
|
+
const cardStyle = {
|
|
2542
|
+
...styles.card,
|
|
2543
|
+
transform: visible ? 'scale(1)' : 'scale(0.96)',
|
|
2261
2544
|
opacity: visible ? 1 : 0,
|
|
2262
|
-
transition: 'opacity 200ms ease, transform 200ms
|
|
2263
|
-
...style
|
|
2545
|
+
transition: 'opacity 200ms ease, transform 200ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
2546
|
+
...style,
|
|
2264
2547
|
};
|
|
2265
|
-
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 }) }));
|
|
2266
2549
|
return createPortal(content, document.body);
|
|
2267
2550
|
}
|
|
2268
2551
|
|