@abstraks-dev/ui-library 2.2.0 → 2.3.0
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/README.md +53 -0
- package/dist/__tests__/Modal.test.js +480 -0
- package/dist/components/Modal.js +195 -0
- package/dist/index.js +56 -0
- package/dist/styles/main.css +218 -0
- package/dist/styles/main.css.map +1 -1
- package/dist/styles/modal.css +332 -0
- package/dist/styles/modal.css.map +1 -0
- package/dist/styles/modal.scss +253 -0
- package/package.json +2 -2
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.Modal = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactDom = require("react-dom");
|
|
9
|
+
var _propTypes = require("prop-types");
|
|
10
|
+
var _icons = require("../icons");
|
|
11
|
+
var _ssrSafeId = require("../utils/ssrSafeId");
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
14
|
+
/**
|
|
15
|
+
* Modal - A stateless, accessible modal dialog component
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Portal rendering to document.body
|
|
19
|
+
* - Multiple sizes (sm, md, lg, xl, full)
|
|
20
|
+
* - Accessible with proper ARIA attributes and focus management
|
|
21
|
+
* - Keyboard support (Escape to close)
|
|
22
|
+
* - Backdrop click to close (optional)
|
|
23
|
+
* - Scroll lock on body
|
|
24
|
+
* - Header, body, and footer sections
|
|
25
|
+
* - Customizable close button
|
|
26
|
+
* - Animation support
|
|
27
|
+
*
|
|
28
|
+
* @component
|
|
29
|
+
* @example
|
|
30
|
+
* <Modal
|
|
31
|
+
* isOpen={true}
|
|
32
|
+
* onClose={() => setIsOpen(false)}
|
|
33
|
+
* title="Confirm Action"
|
|
34
|
+
* size="md"
|
|
35
|
+
* >
|
|
36
|
+
* <p>Are you sure you want to continue?</p>
|
|
37
|
+
* </Modal>
|
|
38
|
+
*/
|
|
39
|
+
const Modal = exports.Modal = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
40
|
+
// Core props
|
|
41
|
+
id,
|
|
42
|
+
className = '',
|
|
43
|
+
// Content props
|
|
44
|
+
title,
|
|
45
|
+
children,
|
|
46
|
+
footer,
|
|
47
|
+
headerContent,
|
|
48
|
+
// Behavior props
|
|
49
|
+
isOpen = false,
|
|
50
|
+
onClose,
|
|
51
|
+
closeOnBackdropClick = true,
|
|
52
|
+
closeOnEscape = true,
|
|
53
|
+
showCloseButton = true,
|
|
54
|
+
preventBodyScroll = true,
|
|
55
|
+
// Appearance props
|
|
56
|
+
size = 'md',
|
|
57
|
+
centered = true,
|
|
58
|
+
// Accessibility props
|
|
59
|
+
'aria-label': ariaLabel,
|
|
60
|
+
'aria-describedby': ariaDescribedBy,
|
|
61
|
+
'aria-labelledby': ariaLabelledBy,
|
|
62
|
+
role = 'dialog',
|
|
63
|
+
// Additional props
|
|
64
|
+
componentName = 'modal',
|
|
65
|
+
...rest
|
|
66
|
+
}, ref) => {
|
|
67
|
+
const generateId = (0, _ssrSafeId.useStableId)('modal');
|
|
68
|
+
const stableId = id || generateId();
|
|
69
|
+
const titleId = `${stableId}-title`;
|
|
70
|
+
const contentId = `${stableId}-content`;
|
|
71
|
+
|
|
72
|
+
// Handle Escape key press
|
|
73
|
+
const handleEscape = (0, _react.useCallback)(event => {
|
|
74
|
+
if (closeOnEscape && event.key === 'Escape' && isOpen) {
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
onClose?.();
|
|
77
|
+
}
|
|
78
|
+
}, [closeOnEscape, isOpen, onClose]);
|
|
79
|
+
|
|
80
|
+
// Handle backdrop click
|
|
81
|
+
const handleBackdropClick = (0, _react.useCallback)(event => {
|
|
82
|
+
if (closeOnBackdropClick && event.target === event.currentTarget) {
|
|
83
|
+
onClose?.();
|
|
84
|
+
}
|
|
85
|
+
}, [closeOnBackdropClick, onClose]);
|
|
86
|
+
|
|
87
|
+
// Manage body scroll lock
|
|
88
|
+
(0, _react.useEffect)(() => {
|
|
89
|
+
if (isOpen && preventBodyScroll) {
|
|
90
|
+
const originalOverflow = document.body.style.overflow;
|
|
91
|
+
const originalPaddingRight = document.body.style.paddingRight;
|
|
92
|
+
|
|
93
|
+
// Get scrollbar width
|
|
94
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
95
|
+
|
|
96
|
+
// Lock scroll
|
|
97
|
+
document.body.style.overflow = 'hidden';
|
|
98
|
+
if (scrollbarWidth > 0) {
|
|
99
|
+
document.body.style.paddingRight = `${scrollbarWidth}px`;
|
|
100
|
+
}
|
|
101
|
+
return () => {
|
|
102
|
+
document.body.style.overflow = originalOverflow;
|
|
103
|
+
document.body.style.paddingRight = originalPaddingRight;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}, [isOpen, preventBodyScroll]);
|
|
107
|
+
|
|
108
|
+
// Add/remove escape key listener
|
|
109
|
+
(0, _react.useEffect)(() => {
|
|
110
|
+
if (isOpen && closeOnEscape) {
|
|
111
|
+
document.addEventListener('keydown', handleEscape);
|
|
112
|
+
return () => {
|
|
113
|
+
document.removeEventListener('keydown', handleEscape);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}, [isOpen, closeOnEscape, handleEscape]);
|
|
117
|
+
|
|
118
|
+
// Focus management
|
|
119
|
+
(0, _react.useEffect)(() => {
|
|
120
|
+
if (isOpen) {
|
|
121
|
+
// Store the currently focused element
|
|
122
|
+
const previousActiveElement = document.activeElement;
|
|
123
|
+
|
|
124
|
+
// Return focus when modal closes
|
|
125
|
+
return () => {
|
|
126
|
+
if (previousActiveElement && previousActiveElement.focus) {
|
|
127
|
+
previousActiveElement.focus();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}, [isOpen]);
|
|
132
|
+
if (!isOpen) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const modalClassName = [componentName, `${componentName}--${size}`, centered && `${componentName}--centered`, className].filter(Boolean).join(' ');
|
|
136
|
+
const modalContent = /*#__PURE__*/_react.default.createElement("div", {
|
|
137
|
+
className: `${componentName}-overlay`,
|
|
138
|
+
onClick: handleBackdropClick
|
|
139
|
+
}, /*#__PURE__*/_react.default.createElement("div", _extends({
|
|
140
|
+
ref: ref,
|
|
141
|
+
id: stableId,
|
|
142
|
+
className: modalClassName,
|
|
143
|
+
role: role,
|
|
144
|
+
"aria-modal": "true",
|
|
145
|
+
"aria-label": ariaLabel || title,
|
|
146
|
+
"aria-labelledby": title ? titleId : ariaLabelledBy,
|
|
147
|
+
"aria-describedby": ariaDescribedBy || contentId
|
|
148
|
+
}, rest), (title || headerContent || showCloseButton) && /*#__PURE__*/_react.default.createElement("div", {
|
|
149
|
+
className: `${componentName}__header`
|
|
150
|
+
}, headerContent || /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, title && /*#__PURE__*/_react.default.createElement("h2", {
|
|
151
|
+
id: titleId,
|
|
152
|
+
className: `${componentName}__title`
|
|
153
|
+
}, title)), showCloseButton && /*#__PURE__*/_react.default.createElement("button", {
|
|
154
|
+
className: `${componentName}__close`,
|
|
155
|
+
onClick: onClose,
|
|
156
|
+
"aria-label": "Close modal",
|
|
157
|
+
type: "button"
|
|
158
|
+
}, /*#__PURE__*/_react.default.createElement(_icons.Close, {
|
|
159
|
+
dimensions: 24
|
|
160
|
+
}))), /*#__PURE__*/_react.default.createElement("div", {
|
|
161
|
+
id: contentId,
|
|
162
|
+
className: `${componentName}__body`
|
|
163
|
+
}, children), footer && /*#__PURE__*/_react.default.createElement("div", {
|
|
164
|
+
className: `${componentName}__footer`
|
|
165
|
+
}, footer)));
|
|
166
|
+
|
|
167
|
+
// Render modal in a portal
|
|
168
|
+
if (typeof window !== 'undefined') {
|
|
169
|
+
return /*#__PURE__*/(0, _reactDom.createPortal)(modalContent, document.body);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
});
|
|
173
|
+
Modal.propTypes = {
|
|
174
|
+
id: _propTypes.string,
|
|
175
|
+
className: _propTypes.string,
|
|
176
|
+
title: _propTypes.string,
|
|
177
|
+
children: _propTypes.node,
|
|
178
|
+
footer: _propTypes.node,
|
|
179
|
+
headerContent: _propTypes.node,
|
|
180
|
+
isOpen: _propTypes.bool,
|
|
181
|
+
onClose: _propTypes.func,
|
|
182
|
+
closeOnBackdropClick: _propTypes.bool,
|
|
183
|
+
closeOnEscape: _propTypes.bool,
|
|
184
|
+
showCloseButton: _propTypes.bool,
|
|
185
|
+
preventBodyScroll: _propTypes.bool,
|
|
186
|
+
size: (0, _propTypes.oneOf)(['sm', 'md', 'lg', 'xl', 'full']),
|
|
187
|
+
centered: _propTypes.bool,
|
|
188
|
+
'aria-label': _propTypes.string,
|
|
189
|
+
'aria-describedby': _propTypes.string,
|
|
190
|
+
'aria-labelledby': _propTypes.string,
|
|
191
|
+
role: _propTypes.string,
|
|
192
|
+
componentName: _propTypes.string
|
|
193
|
+
};
|
|
194
|
+
Modal.displayName = 'Modal';
|
|
195
|
+
var _default = exports.default = Modal;
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ var _exportNames = {
|
|
|
24
24
|
Hero: true,
|
|
25
25
|
Label: true,
|
|
26
26
|
Loader: true,
|
|
27
|
+
Modal: true,
|
|
27
28
|
Paragraph: true,
|
|
28
29
|
Radio: true,
|
|
29
30
|
Search: true,
|
|
@@ -38,8 +39,14 @@ var _exportNames = {
|
|
|
38
39
|
ArrowRight: true,
|
|
39
40
|
BookOpen: true,
|
|
40
41
|
CameraIcon: true,
|
|
42
|
+
Check: true,
|
|
41
43
|
CheckCircle: true,
|
|
42
44
|
ChevronDown: true,
|
|
45
|
+
even: true,
|
|
46
|
+
ChevronLeft: true,
|
|
47
|
+
ChevronRight: true,
|
|
48
|
+
ChevronRightCircle: true,
|
|
49
|
+
ChevronUpCircle: true,
|
|
43
50
|
Close: true,
|
|
44
51
|
Comment: true,
|
|
45
52
|
EditSquare: true,
|
|
@@ -151,6 +158,12 @@ Object.defineProperty(exports, "CaretDown", {
|
|
|
151
158
|
return _CaretDown.default;
|
|
152
159
|
}
|
|
153
160
|
});
|
|
161
|
+
Object.defineProperty(exports, "Check", {
|
|
162
|
+
enumerable: true,
|
|
163
|
+
get: function () {
|
|
164
|
+
return _Check.Check;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
154
167
|
Object.defineProperty(exports, "CheckCircle", {
|
|
155
168
|
enumerable: true,
|
|
156
169
|
get: function () {
|
|
@@ -169,6 +182,30 @@ Object.defineProperty(exports, "ChevronDown", {
|
|
|
169
182
|
return _ChevronDown.ChevronDown;
|
|
170
183
|
}
|
|
171
184
|
});
|
|
185
|
+
Object.defineProperty(exports, "ChevronLeft", {
|
|
186
|
+
enumerable: true,
|
|
187
|
+
get: function () {
|
|
188
|
+
return _ChevronLeft.ChevronLeft;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
Object.defineProperty(exports, "ChevronRight", {
|
|
192
|
+
enumerable: true,
|
|
193
|
+
get: function () {
|
|
194
|
+
return _ChevronRight.ChevronRight;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
Object.defineProperty(exports, "ChevronRightCircle", {
|
|
198
|
+
enumerable: true,
|
|
199
|
+
get: function () {
|
|
200
|
+
return _ChevronRightCircle.ChevronRightCircle;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
Object.defineProperty(exports, "ChevronUpCircle", {
|
|
204
|
+
enumerable: true,
|
|
205
|
+
get: function () {
|
|
206
|
+
return _ChevronUpCircle.ChevronUpCircle;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
172
209
|
Object.defineProperty(exports, "Close", {
|
|
173
210
|
enumerable: true,
|
|
174
211
|
get: function () {
|
|
@@ -319,6 +356,12 @@ Object.defineProperty(exports, "Magnify", {
|
|
|
319
356
|
return _Magnify.Magnify;
|
|
320
357
|
}
|
|
321
358
|
});
|
|
359
|
+
Object.defineProperty(exports, "Modal", {
|
|
360
|
+
enumerable: true,
|
|
361
|
+
get: function () {
|
|
362
|
+
return _Modal.default;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
322
365
|
Object.defineProperty(exports, "News", {
|
|
323
366
|
enumerable: true,
|
|
324
367
|
get: function () {
|
|
@@ -397,6 +440,12 @@ Object.defineProperty(exports, "TrashX", {
|
|
|
397
440
|
return _TrashX.TrashX;
|
|
398
441
|
}
|
|
399
442
|
});
|
|
443
|
+
Object.defineProperty(exports, "even", {
|
|
444
|
+
enumerable: true,
|
|
445
|
+
get: function () {
|
|
446
|
+
return _ChevronDownCircle.even;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
400
449
|
var _utils = require("./utils");
|
|
401
450
|
Object.keys(_utils).forEach(function (key) {
|
|
402
451
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -441,6 +490,7 @@ var _Heading = _interopRequireDefault(require("./components/Heading"));
|
|
|
441
490
|
var _Hero = _interopRequireDefault(require("./components/Hero"));
|
|
442
491
|
var _Label = _interopRequireDefault(require("./components/Label"));
|
|
443
492
|
var _Loader = _interopRequireDefault(require("./components/Loader"));
|
|
493
|
+
var _Modal = _interopRequireDefault(require("./components/Modal"));
|
|
444
494
|
var _Paragraph = _interopRequireDefault(require("./components/Paragraph"));
|
|
445
495
|
var _Radio = require("./components/Radio");
|
|
446
496
|
var _Search = require("./components/Search");
|
|
@@ -455,8 +505,14 @@ var _ArrowIcon = require("./icons/ArrowIcon");
|
|
|
455
505
|
var _ArrowRight = require("./icons/ArrowRight");
|
|
456
506
|
var _BookOpen = require("./icons/BookOpen");
|
|
457
507
|
var _Camera = require("./icons/Camera");
|
|
508
|
+
var _Check = require("./icons/Check");
|
|
458
509
|
var _CheckCircle = require("./icons/CheckCircle");
|
|
459
510
|
var _ChevronDown = require("./icons/ChevronDown");
|
|
511
|
+
var _ChevronDownCircle = require("./icons/ChevronDownCircle");
|
|
512
|
+
var _ChevronLeft = require("./icons/ChevronLeft");
|
|
513
|
+
var _ChevronRight = require("./icons/ChevronRight");
|
|
514
|
+
var _ChevronRightCircle = require("./icons/ChevronRightCircle");
|
|
515
|
+
var _ChevronUpCircle = require("./icons/ChevronUpCircle");
|
|
460
516
|
var _Close = require("./icons/Close");
|
|
461
517
|
var _Comment = require("./icons/Comment");
|
|
462
518
|
var _EditSquare = require("./icons/EditSquare");
|
package/dist/styles/main.css
CHANGED
|
@@ -7545,6 +7545,224 @@ body.scroll-locked {
|
|
|
7545
7545
|
border: 0 !important;
|
|
7546
7546
|
}
|
|
7547
7547
|
|
|
7548
|
+
.modal-overlay {
|
|
7549
|
+
position: fixed;
|
|
7550
|
+
top: 0;
|
|
7551
|
+
left: 0;
|
|
7552
|
+
right: 0;
|
|
7553
|
+
bottom: 0;
|
|
7554
|
+
background-color: rgba(0, 0, 0, 0.6);
|
|
7555
|
+
backdrop-filter: blur(4px);
|
|
7556
|
+
z-index: 9999;
|
|
7557
|
+
display: flex;
|
|
7558
|
+
align-items: center;
|
|
7559
|
+
justify-content: center;
|
|
7560
|
+
padding: 1rem;
|
|
7561
|
+
animation: fadeIn 0.2s ease-out;
|
|
7562
|
+
overflow-y: auto;
|
|
7563
|
+
}
|
|
7564
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7565
|
+
.modal-overlay {
|
|
7566
|
+
animation: none;
|
|
7567
|
+
}
|
|
7568
|
+
}
|
|
7569
|
+
|
|
7570
|
+
.modal {
|
|
7571
|
+
background: #fff;
|
|
7572
|
+
border-radius: 8px;
|
|
7573
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
7574
|
+
display: flex;
|
|
7575
|
+
flex-direction: column;
|
|
7576
|
+
max-height: calc(100vh - 2rem);
|
|
7577
|
+
width: 100%;
|
|
7578
|
+
animation: slideIn 0.3s ease-out;
|
|
7579
|
+
position: relative;
|
|
7580
|
+
}
|
|
7581
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7582
|
+
.modal {
|
|
7583
|
+
animation: none;
|
|
7584
|
+
}
|
|
7585
|
+
}
|
|
7586
|
+
@media (prefers-color-scheme: dark) {
|
|
7587
|
+
.modal {
|
|
7588
|
+
background: #1e1e1e;
|
|
7589
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
|
|
7590
|
+
}
|
|
7591
|
+
}
|
|
7592
|
+
.modal--sm {
|
|
7593
|
+
max-width: 400px;
|
|
7594
|
+
}
|
|
7595
|
+
.modal--md {
|
|
7596
|
+
max-width: 600px;
|
|
7597
|
+
}
|
|
7598
|
+
.modal--lg {
|
|
7599
|
+
max-width: 800px;
|
|
7600
|
+
}
|
|
7601
|
+
.modal--xl {
|
|
7602
|
+
max-width: 1200px;
|
|
7603
|
+
}
|
|
7604
|
+
.modal--full {
|
|
7605
|
+
max-width: calc(100vw - 2rem);
|
|
7606
|
+
max-height: calc(100vh - 2rem);
|
|
7607
|
+
}
|
|
7608
|
+
.modal--centered {
|
|
7609
|
+
margin: auto;
|
|
7610
|
+
}
|
|
7611
|
+
.modal__header {
|
|
7612
|
+
display: flex;
|
|
7613
|
+
align-items: center;
|
|
7614
|
+
justify-content: space-between;
|
|
7615
|
+
padding: 1.5rem;
|
|
7616
|
+
border-bottom: 1px solid #e9ecef;
|
|
7617
|
+
flex-shrink: 0;
|
|
7618
|
+
}
|
|
7619
|
+
@media (prefers-color-scheme: dark) {
|
|
7620
|
+
.modal__header {
|
|
7621
|
+
border-bottom-color: #333;
|
|
7622
|
+
}
|
|
7623
|
+
}
|
|
7624
|
+
.modal__title {
|
|
7625
|
+
margin: 0;
|
|
7626
|
+
font-size: 1.25rem;
|
|
7627
|
+
font-weight: 600;
|
|
7628
|
+
color: #212529;
|
|
7629
|
+
flex: 1;
|
|
7630
|
+
}
|
|
7631
|
+
@media (prefers-color-scheme: dark) {
|
|
7632
|
+
.modal__title {
|
|
7633
|
+
color: #fff;
|
|
7634
|
+
}
|
|
7635
|
+
}
|
|
7636
|
+
.modal__close {
|
|
7637
|
+
display: flex;
|
|
7638
|
+
align-items: center;
|
|
7639
|
+
justify-content: center;
|
|
7640
|
+
background: transparent;
|
|
7641
|
+
border: none;
|
|
7642
|
+
padding: 0.5rem;
|
|
7643
|
+
margin: -0.5rem -0.5rem -0.5rem 1rem;
|
|
7644
|
+
cursor: pointer;
|
|
7645
|
+
color: #6c757d;
|
|
7646
|
+
border-radius: 4px;
|
|
7647
|
+
transition: all 0.15s ease;
|
|
7648
|
+
flex-shrink: 0;
|
|
7649
|
+
}
|
|
7650
|
+
.modal__close:hover {
|
|
7651
|
+
background: #f8f9fa;
|
|
7652
|
+
color: #212529;
|
|
7653
|
+
}
|
|
7654
|
+
@media (prefers-color-scheme: dark) {
|
|
7655
|
+
.modal__close:hover {
|
|
7656
|
+
background: #333;
|
|
7657
|
+
color: #fff;
|
|
7658
|
+
}
|
|
7659
|
+
}
|
|
7660
|
+
.modal__close:focus-visible {
|
|
7661
|
+
outline: 2px solid #009900;
|
|
7662
|
+
outline-offset: 2px;
|
|
7663
|
+
}
|
|
7664
|
+
.modal__close svg {
|
|
7665
|
+
display: block;
|
|
7666
|
+
}
|
|
7667
|
+
.modal__body {
|
|
7668
|
+
padding: 1.5rem;
|
|
7669
|
+
overflow-y: auto;
|
|
7670
|
+
flex: 1;
|
|
7671
|
+
color: #495057;
|
|
7672
|
+
}
|
|
7673
|
+
@media (prefers-color-scheme: dark) {
|
|
7674
|
+
.modal__body {
|
|
7675
|
+
color: #dee2e6;
|
|
7676
|
+
}
|
|
7677
|
+
}
|
|
7678
|
+
.modal__body::-webkit-scrollbar {
|
|
7679
|
+
width: 8px;
|
|
7680
|
+
}
|
|
7681
|
+
.modal__body::-webkit-scrollbar-track {
|
|
7682
|
+
background: #f8f9fa;
|
|
7683
|
+
border-radius: 4px;
|
|
7684
|
+
}
|
|
7685
|
+
@media (prefers-color-scheme: dark) {
|
|
7686
|
+
.modal__body::-webkit-scrollbar-track {
|
|
7687
|
+
background: #2a2a2a;
|
|
7688
|
+
}
|
|
7689
|
+
}
|
|
7690
|
+
.modal__body::-webkit-scrollbar-thumb {
|
|
7691
|
+
background: #ced4da;
|
|
7692
|
+
border-radius: 4px;
|
|
7693
|
+
}
|
|
7694
|
+
.modal__body::-webkit-scrollbar-thumb:hover {
|
|
7695
|
+
background: #adb5bd;
|
|
7696
|
+
}
|
|
7697
|
+
@media (prefers-color-scheme: dark) {
|
|
7698
|
+
.modal__body::-webkit-scrollbar-thumb {
|
|
7699
|
+
background: #555;
|
|
7700
|
+
}
|
|
7701
|
+
.modal__body::-webkit-scrollbar-thumb:hover {
|
|
7702
|
+
background: #666;
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
.modal__footer {
|
|
7706
|
+
display: flex;
|
|
7707
|
+
align-items: center;
|
|
7708
|
+
justify-content: flex-end;
|
|
7709
|
+
gap: 0.75rem;
|
|
7710
|
+
padding: 1.5rem;
|
|
7711
|
+
border-top: 1px solid #e9ecef;
|
|
7712
|
+
flex-shrink: 0;
|
|
7713
|
+
}
|
|
7714
|
+
@media (prefers-color-scheme: dark) {
|
|
7715
|
+
.modal__footer {
|
|
7716
|
+
border-top-color: #333;
|
|
7717
|
+
}
|
|
7718
|
+
}
|
|
7719
|
+
|
|
7720
|
+
@keyframes fadeIn {
|
|
7721
|
+
from {
|
|
7722
|
+
opacity: 0;
|
|
7723
|
+
}
|
|
7724
|
+
to {
|
|
7725
|
+
opacity: 1;
|
|
7726
|
+
}
|
|
7727
|
+
}
|
|
7728
|
+
@keyframes slideIn {
|
|
7729
|
+
from {
|
|
7730
|
+
opacity: 0;
|
|
7731
|
+
transform: translateY(-20px) scale(0.95);
|
|
7732
|
+
}
|
|
7733
|
+
to {
|
|
7734
|
+
opacity: 1;
|
|
7735
|
+
transform: translateY(0) scale(1);
|
|
7736
|
+
}
|
|
7737
|
+
}
|
|
7738
|
+
@media (max-width: 640px) {
|
|
7739
|
+
.modal-overlay {
|
|
7740
|
+
padding: 0.5rem;
|
|
7741
|
+
}
|
|
7742
|
+
.modal {
|
|
7743
|
+
max-height: calc(100vh - 1rem);
|
|
7744
|
+
}
|
|
7745
|
+
.modal--sm, .modal--md, .modal--lg, .modal--xl {
|
|
7746
|
+
max-width: 100%;
|
|
7747
|
+
}
|
|
7748
|
+
.modal__header, .modal__body, .modal__footer {
|
|
7749
|
+
padding: 1rem;
|
|
7750
|
+
}
|
|
7751
|
+
.modal__title {
|
|
7752
|
+
font-size: 1.125rem;
|
|
7753
|
+
}
|
|
7754
|
+
}
|
|
7755
|
+
@media (prefers-contrast: high) {
|
|
7756
|
+
.modal {
|
|
7757
|
+
border: 2px solid currentColor;
|
|
7758
|
+
}
|
|
7759
|
+
.modal__header, .modal__footer {
|
|
7760
|
+
border-color: currentColor;
|
|
7761
|
+
}
|
|
7762
|
+
.modal__close:focus-visible {
|
|
7763
|
+
outline-width: 3px;
|
|
7764
|
+
}
|
|
7765
|
+
}
|
|
7548
7766
|
.logo {
|
|
7549
7767
|
width: 50%;
|
|
7550
7768
|
display: inline-flex;
|