@mackin.com/styleguide 8.11.2 → 8.12.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/index.d.ts +8 -2
- package/index.js +233 -232
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ interface AutocompleteProps<T extends AutocompleteValue> {
|
|
|
54
54
|
/** Defaults to 0ms. */
|
|
55
55
|
getOptionsDebounceMs?: number;
|
|
56
56
|
autoFocus?: boolean;
|
|
57
|
+
/** Options passed to the lodash debounce function. */
|
|
58
|
+
debounceOptions?: {
|
|
59
|
+
leading: boolean;
|
|
60
|
+
trailing: boolean;
|
|
61
|
+
};
|
|
57
62
|
/** Will enable scrolling in the results list. */
|
|
58
63
|
allowScroll?: boolean;
|
|
59
64
|
onChange: (value: string) => void;
|
|
@@ -467,8 +472,6 @@ interface ModalProps {
|
|
|
467
472
|
__debug?: boolean;
|
|
468
473
|
onClick?: () => void;
|
|
469
474
|
}
|
|
470
|
-
/** Add to fixed positioned elements so their contents do not jump around when scrolling is disabled. */
|
|
471
|
-
declare const modalScrollFixClassName = "modal-scroll-fix";
|
|
472
475
|
declare const Modal: (p: ModalProps) => React__default.ReactPortal | null;
|
|
473
476
|
|
|
474
477
|
declare const Nav: (props: {
|
|
@@ -1149,4 +1152,7 @@ interface TabContainerProps {
|
|
|
1149
1152
|
}
|
|
1150
1153
|
declare const TabContainer: (p: TabContainerProps) => JSX.Element;
|
|
1151
1154
|
|
|
1155
|
+
/** Add to fixed positioned elements so their contents do not jump around when scrolling is disabled. */
|
|
1156
|
+
declare const modalScrollFixClassName = "modal-scroll-fix";
|
|
1157
|
+
|
|
1152
1158
|
export { Accordian, AccordianProps, Alignment, Autocomplete, AutocompleteProps, AutocompleteValue, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, ButtonProps, Calendar, CalendarProps, Checkbox, CheckboxProps, ConfirmModal, ConfirmModalProps, CopyButton, DateInput, DateInputProps, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, FormProps, GlobalStyles, Header, Highlight, ICONS, Icon, Image, ImageProps, InfoPanel, InfoTip, InfoTipProps, Input, InputProps, ItemPager, Label, LabelProps, Link, LinkProps, List, ListItem, ListItemProps, ListProps, MackinTheme, Modal, ModalProps, Nav, NormalizeCss, NumberInput, NumberInputProps, OmniLink, OmniLinkProps, PagedResult, Pager, PagerProps, Picker, PickerOption, PickerProps, PickerValue, Popover, ProgressBar, ProgressBarProps, SearchBox, SearchBoxProps, Slider, SliderProps, SliderValue, TabContainer, TabContainerProps, TabHeader, TabHeaderProps, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, TextAreaProps, TextInput, TextInputProps, TextProps, Th, ThSort, ThemeProvider, ThemeRenderer, ToggleButton, ToggleButtonGroup, ToggleButtonGroupProps, ToggleButtonProps, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
|
package/index.js
CHANGED
|
@@ -1175,239 +1175,8 @@ const Backdrop$1 = (props) => {
|
|
|
1175
1175
|
}, ref: backdrop, className: css.cx('backdrop', styles, props.className) }, props.children));
|
|
1176
1176
|
};
|
|
1177
1177
|
|
|
1178
|
-
/** useEffect but it will only fire when the actual truthiness of the value changes.
|
|
1179
|
-
* Use for comparing previous states to next states without all the bullshit around useEffect and component mounting.
|
|
1180
|
-
*/
|
|
1181
|
-
const useBooleanChanged = (effect, dep) => {
|
|
1182
|
-
/*
|
|
1183
|
-
Why?
|
|
1184
|
-
useEffect with a dependency array will fire once on mount even though the dependency list doesn't change.
|
|
1185
|
-
Components like Modal need to communicate when their show status changes.
|
|
1186
|
-
useIgnoreMount is not enough because it only ignores the first render and is therefore a kludge.
|
|
1187
|
-
This is what we want regardless of mount status:
|
|
1188
|
-
true > false = Change
|
|
1189
|
-
false > true = Change
|
|
1190
|
-
true > true = No Change
|
|
1191
|
-
false > false = No Change
|
|
1192
|
-
undefined > false = No Change
|
|
1193
|
-
undefined > true = Change
|
|
1194
|
-
*/
|
|
1195
|
-
const lastValue = React.useRef(undefined);
|
|
1196
|
-
React.useEffect(() => {
|
|
1197
|
-
//console.log('[useBooleanChanged] useEffect called with', dep, 'was', lastValue.current ?? 'undefined')
|
|
1198
|
-
if (!!lastValue.current !== !!dep) {
|
|
1199
|
-
const previous = lastValue.current;
|
|
1200
|
-
lastValue.current = dep;
|
|
1201
|
-
effect(!!lastValue.current, !!previous);
|
|
1202
|
-
//console.log('[useBooleanChanged] change called')
|
|
1203
|
-
}
|
|
1204
|
-
}, [dep]);
|
|
1205
|
-
};
|
|
1206
|
-
|
|
1207
|
-
const useLogger = (componentName, enabled) => {
|
|
1208
|
-
return (...messages) => {
|
|
1209
|
-
if (enabled) {
|
|
1210
|
-
// tslint:disable-next-line
|
|
1211
|
-
console.log(`[${componentName}]`, ...messages);
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
};
|
|
1215
|
-
|
|
1216
|
-
// Taken from: https://github.com/react-bootstrap/dom-helpers/blob/master/src/scrollbarSize.ts
|
|
1217
|
-
const canUseDom = !!(typeof window !== 'undefined' &&
|
|
1218
|
-
window.document &&
|
|
1219
|
-
window.document.createElement);
|
|
1220
|
-
let size;
|
|
1221
|
-
/** Tells you actual width of the scroll bar. This can vary by browser. */
|
|
1222
|
-
const useScrollbarSize = (recalc) => {
|
|
1223
|
-
if ((!size && size !== 0) || recalc) {
|
|
1224
|
-
if (canUseDom) {
|
|
1225
|
-
const scrollDiv = document.createElement('div');
|
|
1226
|
-
scrollDiv.style.position = 'absolute';
|
|
1227
|
-
scrollDiv.style.top = '-9999px';
|
|
1228
|
-
scrollDiv.style.width = '50px';
|
|
1229
|
-
scrollDiv.style.height = '50px';
|
|
1230
|
-
scrollDiv.style.overflow = 'scroll';
|
|
1231
|
-
document.body.appendChild(scrollDiv);
|
|
1232
|
-
size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
1233
|
-
document.body.removeChild(scrollDiv);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
return size;
|
|
1237
|
-
};
|
|
1238
|
-
|
|
1239
1178
|
/** Add to fixed positioned elements so their contents do not jump around when scrolling is disabled. */
|
|
1240
|
-
const modalScrollFixClassName = 'modal-scroll-fix';
|
|
1241
|
-
const Modal = (p) => {
|
|
1242
|
-
var _a, _b, _c, _d;
|
|
1243
|
-
const backdrop = React.useContext(BackdropContext);
|
|
1244
|
-
const mouseDownElement = React.useRef(undefined);
|
|
1245
|
-
const theme = useThemeSafely();
|
|
1246
|
-
const hasHeader = p.closeButton || p.heading;
|
|
1247
|
-
const contentRef = React__default['default'].useRef(null);
|
|
1248
|
-
const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
1249
|
-
const showing = React.useRef(p.show);
|
|
1250
|
-
const bodyStyles = React.useRef('');
|
|
1251
|
-
const fixedElementStyles = React.useRef('');
|
|
1252
|
-
const addScrollStyles = () => {
|
|
1253
|
-
var _a, _b, _c, _d;
|
|
1254
|
-
if (!bodyStyles.current) {
|
|
1255
|
-
bodyStyles.current = css.css({
|
|
1256
|
-
label: 'ModalBodyOverrides_' + ((_b = (_a = p.id) === null || _a === void 0 ? void 0 : _a.replace(/\s+/, '')) !== null && _b !== void 0 ? _b : nanoid.nanoid()),
|
|
1257
|
-
overflow: 'hidden',
|
|
1258
|
-
paddingRight: `${useScrollbarSize()}px`
|
|
1259
|
-
});
|
|
1260
|
-
log('creating singleton bodyStyles', bodyStyles.current);
|
|
1261
|
-
}
|
|
1262
|
-
if (!fixedElementStyles.current) {
|
|
1263
|
-
fixedElementStyles.current = css.css({
|
|
1264
|
-
label: 'ModalElementOverrides_' + ((_d = (_c = p.id) === null || _c === void 0 ? void 0 : _c.replace(/\s+/, '')) !== null && _d !== void 0 ? _d : nanoid.nanoid()),
|
|
1265
|
-
paddingRight: `${useScrollbarSize()}px`
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
document.body.classList.add(bodyStyles.current);
|
|
1269
|
-
Array.from(document.querySelectorAll(`.${modalScrollFixClassName}`)).forEach(e => {
|
|
1270
|
-
e.classList.add(fixedElementStyles.current);
|
|
1271
|
-
});
|
|
1272
|
-
};
|
|
1273
|
-
const tryRemoveScrollStyles = () => {
|
|
1274
|
-
if (bodyStyles.current) {
|
|
1275
|
-
log('removing singleton', bodyStyles.current);
|
|
1276
|
-
document.body.classList.remove(bodyStyles.current);
|
|
1277
|
-
}
|
|
1278
|
-
if (fixedElementStyles.current) {
|
|
1279
|
-
Array.from(document.querySelectorAll(`.${modalScrollFixClassName}`)).forEach(e => {
|
|
1280
|
-
e.classList.remove(fixedElementStyles.current);
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
};
|
|
1284
|
-
React.useEffect(() => {
|
|
1285
|
-
log('mounted');
|
|
1286
|
-
return () => {
|
|
1287
|
-
var _a;
|
|
1288
|
-
if (showing.current) {
|
|
1289
|
-
log(`un-mount in progress and this modal is showing. decrement the backdrop and try to remove singleton body styles.`);
|
|
1290
|
-
backdrop.setShow(false, (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal');
|
|
1291
|
-
log('backdrop.setShow', false);
|
|
1292
|
-
tryRemoveScrollStyles();
|
|
1293
|
-
}
|
|
1294
|
-
else {
|
|
1295
|
-
log(`un-mount in progress but this modal is not showing. do nothing with the backdrop.`);
|
|
1296
|
-
}
|
|
1297
|
-
log('un-mounted');
|
|
1298
|
-
};
|
|
1299
|
-
}, []);
|
|
1300
|
-
useBooleanChanged((show, previousShow) => {
|
|
1301
|
-
var _a;
|
|
1302
|
-
log('show changed', `${previousShow !== null && previousShow !== void 0 ? previousShow : 'undefined'} > ${show}`);
|
|
1303
|
-
backdrop.setShow(show, (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal');
|
|
1304
|
-
showing.current = show;
|
|
1305
|
-
log('backdrop.setShow', show);
|
|
1306
|
-
if (show) {
|
|
1307
|
-
log('this modal is showing. adding singleton bodyStyles', bodyStyles.current);
|
|
1308
|
-
addScrollStyles();
|
|
1309
|
-
}
|
|
1310
|
-
else {
|
|
1311
|
-
log('this modal is hiding. try removing singleton bodyStyles');
|
|
1312
|
-
tryRemoveScrollStyles();
|
|
1313
|
-
}
|
|
1314
|
-
}, p.show);
|
|
1315
|
-
React__default['default'].useLayoutEffect(() => {
|
|
1316
|
-
var _a;
|
|
1317
|
-
if (p.show === true) {
|
|
1318
|
-
const focusSelector = (_a = p.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
|
|
1319
|
-
// still need to wait for the next tick so the children are all rendered.
|
|
1320
|
-
setTimeout(() => {
|
|
1321
|
-
var _a;
|
|
1322
|
-
const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
|
|
1323
|
-
element === null || element === void 0 ? void 0 : element.focus();
|
|
1324
|
-
log('set focus', focusSelector);
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
}, [p.show]);
|
|
1328
|
-
const modalBodyStyles = css.css({
|
|
1329
|
-
maxHeight: p.scrollable ? undefined : '99vh',
|
|
1330
|
-
overflow: 'hidden',
|
|
1331
|
-
zIndex: theme.zIndexes.modal,
|
|
1332
|
-
cursor: 'default',
|
|
1333
|
-
margin: '1rem',
|
|
1334
|
-
backgroundColor: p.noBackground ? undefined : theme.colors.modalBg,
|
|
1335
|
-
border: p.noBackground ? undefined : theme.controls.border,
|
|
1336
|
-
boxShadow: p.noBackground ? undefined : theme.controls.boxShadow,
|
|
1337
|
-
maxWidth: (_c = p.maxWidth) !== null && _c !== void 0 ? _c : theme.breakpoints.tablet,
|
|
1338
|
-
minWidth: (_d = p.minWidth) !== null && _d !== void 0 ? _d : (hasHeader ? '250px' : undefined),
|
|
1339
|
-
opacity: p.show ? 1 : 0,
|
|
1340
|
-
fontSize: theme.fonts.size,
|
|
1341
|
-
fontFamily: theme.fonts.family,
|
|
1342
|
-
fontWeight: 'normal',
|
|
1343
|
-
'&:focus': {
|
|
1344
|
-
outline: 'none'
|
|
1345
|
-
}
|
|
1346
|
-
});
|
|
1347
|
-
const modalHeaderStyles = css.cx(css.css({
|
|
1348
|
-
display: 'flex',
|
|
1349
|
-
justifyContent: 'space-between',
|
|
1350
|
-
alignItems: 'center',
|
|
1351
|
-
backgroundColor: theme.colors.header,
|
|
1352
|
-
padding: '1rem',
|
|
1353
|
-
color: theme.colors.headerFont
|
|
1354
|
-
}), p.headerClassName);
|
|
1355
|
-
const modalContainerStyles = css.css([{
|
|
1356
|
-
position: 'fixed',
|
|
1357
|
-
height: '100%',
|
|
1358
|
-
width: '100%',
|
|
1359
|
-
backgroundColor: "transparent",
|
|
1360
|
-
display: 'flex',
|
|
1361
|
-
justifyContent: 'center',
|
|
1362
|
-
alignItems: 'center',
|
|
1363
|
-
cursor: p.onClick ? 'pointer' : 'default'
|
|
1364
|
-
}, p.scrollable && {
|
|
1365
|
-
overflowY: 'auto',
|
|
1366
|
-
overflowX: 'hidden',
|
|
1367
|
-
alignItems: 'flex-start'
|
|
1368
|
-
}]);
|
|
1369
|
-
if (p.show) {
|
|
1370
|
-
const backdropContainer = document.getElementById(backdrop.portalId);
|
|
1371
|
-
if (backdropContainer) {
|
|
1372
|
-
return reactDom.createPortal((React__default['default'].createElement("div", { onClick: e => {
|
|
1373
|
-
e.stopPropagation();
|
|
1374
|
-
if (!mouseDownElement.current) {
|
|
1375
|
-
if (p.onClick) {
|
|
1376
|
-
log('backdropContainer onClick');
|
|
1377
|
-
p.onClick();
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
mouseDownElement.current = undefined;
|
|
1381
|
-
}, className: css.cx('modalContainer', modalContainerStyles) },
|
|
1382
|
-
React__default['default'].createElement("div", { id: p.id, ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
|
|
1383
|
-
mouseDownElement.current = e.target;
|
|
1384
|
-
e.stopPropagation();
|
|
1385
|
-
}, onMouseUp: e => {
|
|
1386
|
-
mouseDownElement.current = undefined;
|
|
1387
|
-
/*
|
|
1388
|
-
MouseDown and MouseUp stopPropagation was added to fix bugs while clicking within the modal.
|
|
1389
|
-
At least in the case of MouseUp, this breaks sliders and the handle grab logic appears to live on window.
|
|
1390
|
-
Turning this off now. Should not cause any issues for MouseUp unlike MouseDown.
|
|
1391
|
-
*/
|
|
1392
|
-
// e.stopPropagation()
|
|
1393
|
-
}, className: css.cx('modalBody', modalBodyStyles, p.className) },
|
|
1394
|
-
React__default['default'].createElement(TabLocker, null,
|
|
1395
|
-
hasHeader && (React__default['default'].createElement("header", { className: css.cx('modalHeader', modalHeaderStyles) },
|
|
1396
|
-
p.heading ? React__default['default'].createElement(Text, { className: css.css({
|
|
1397
|
-
margin: 0,
|
|
1398
|
-
flexGrow: 1
|
|
1399
|
-
}), tag: "h1", bold: true }, p.heading) : React__default['default'].createElement("span", null),
|
|
1400
|
-
p.closeButton && p.onClick ? React__default['default'].createElement(Button, { className: css.cx('modalCloseButton', css.css({
|
|
1401
|
-
color: theme.colors.headerFont,
|
|
1402
|
-
marginLeft: '1rem',
|
|
1403
|
-
backgroundColor: 'transparent'
|
|
1404
|
-
})), variant: "icon", onClick: p.onClick },
|
|
1405
|
-
React__default['default'].createElement(Icon, { id: "close" })) : React__default['default'].createElement("span", null))),
|
|
1406
|
-
p.children)))), backdropContainer);
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
return null;
|
|
1410
|
-
};
|
|
1179
|
+
const modalScrollFixClassName = 'modal-scroll-fix';
|
|
1411
1180
|
|
|
1412
1181
|
/** useEffect but ignores the first call on component mount. */
|
|
1413
1182
|
const useIgnoreMount = (effect, deps) => {
|
|
@@ -1422,6 +1191,15 @@ const useIgnoreMount = (effect, deps) => {
|
|
|
1422
1191
|
}, deps);
|
|
1423
1192
|
};
|
|
1424
1193
|
|
|
1194
|
+
const useLogger = (componentName, enabled) => {
|
|
1195
|
+
return (...messages) => {
|
|
1196
|
+
if (enabled) {
|
|
1197
|
+
// tslint:disable-next-line
|
|
1198
|
+
console.log(`[${componentName}]`, ...messages);
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1425
1203
|
const portalId = 'backdrop';
|
|
1426
1204
|
const BackdropContext = React__default['default'].createContext({
|
|
1427
1205
|
showing: false,
|
|
@@ -1691,6 +1469,229 @@ const Checkbox = (props) => {
|
|
|
1691
1469
|
props.children)));
|
|
1692
1470
|
};
|
|
1693
1471
|
|
|
1472
|
+
/** useEffect but it will only fire when the actual truthiness of the value changes.
|
|
1473
|
+
* Use for comparing previous states to next states without all the bullshit around useEffect and component mounting.
|
|
1474
|
+
*/
|
|
1475
|
+
const useBooleanChanged = (effect, dep) => {
|
|
1476
|
+
/*
|
|
1477
|
+
Why?
|
|
1478
|
+
useEffect with a dependency array will fire once on mount even though the dependency list doesn't change.
|
|
1479
|
+
Components like Modal need to communicate when their show status changes.
|
|
1480
|
+
useIgnoreMount is not enough because it only ignores the first render and is therefore a kludge.
|
|
1481
|
+
This is what we want regardless of mount status:
|
|
1482
|
+
true > false = Change
|
|
1483
|
+
false > true = Change
|
|
1484
|
+
true > true = No Change
|
|
1485
|
+
false > false = No Change
|
|
1486
|
+
undefined > false = No Change
|
|
1487
|
+
undefined > true = Change
|
|
1488
|
+
*/
|
|
1489
|
+
const lastValue = React.useRef(undefined);
|
|
1490
|
+
React.useEffect(() => {
|
|
1491
|
+
//console.log('[useBooleanChanged] useEffect called with', dep, 'was', lastValue.current ?? 'undefined')
|
|
1492
|
+
if (!!lastValue.current !== !!dep) {
|
|
1493
|
+
const previous = lastValue.current;
|
|
1494
|
+
lastValue.current = dep;
|
|
1495
|
+
effect(!!lastValue.current, !!previous);
|
|
1496
|
+
//console.log('[useBooleanChanged] change called')
|
|
1497
|
+
}
|
|
1498
|
+
}, [dep]);
|
|
1499
|
+
};
|
|
1500
|
+
|
|
1501
|
+
// Taken from: https://github.com/react-bootstrap/dom-helpers/blob/master/src/scrollbarSize.ts
|
|
1502
|
+
const canUseDom = !!(typeof window !== 'undefined' &&
|
|
1503
|
+
window.document &&
|
|
1504
|
+
window.document.createElement);
|
|
1505
|
+
let size;
|
|
1506
|
+
/** Tells you actual width of the scroll bar. This can vary by browser. */
|
|
1507
|
+
const useScrollbarSize = (recalc) => {
|
|
1508
|
+
if ((!size && size !== 0) || recalc) {
|
|
1509
|
+
if (canUseDom) {
|
|
1510
|
+
const scrollDiv = document.createElement('div');
|
|
1511
|
+
scrollDiv.style.position = 'absolute';
|
|
1512
|
+
scrollDiv.style.top = '-9999px';
|
|
1513
|
+
scrollDiv.style.width = '50px';
|
|
1514
|
+
scrollDiv.style.height = '50px';
|
|
1515
|
+
scrollDiv.style.overflow = 'scroll';
|
|
1516
|
+
document.body.appendChild(scrollDiv);
|
|
1517
|
+
size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
1518
|
+
document.body.removeChild(scrollDiv);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
return size;
|
|
1522
|
+
};
|
|
1523
|
+
|
|
1524
|
+
const Modal = (p) => {
|
|
1525
|
+
var _a, _b, _c, _d;
|
|
1526
|
+
const backdrop = React.useContext(BackdropContext);
|
|
1527
|
+
const mouseDownElement = React.useRef(undefined);
|
|
1528
|
+
const theme = useThemeSafely();
|
|
1529
|
+
const hasHeader = p.closeButton || p.heading;
|
|
1530
|
+
const contentRef = React__default['default'].useRef(null);
|
|
1531
|
+
const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
1532
|
+
const showing = React.useRef(p.show);
|
|
1533
|
+
const bodyStyles = React.useRef('');
|
|
1534
|
+
const fixedElementStyles = React.useRef('');
|
|
1535
|
+
const addScrollStyles = () => {
|
|
1536
|
+
var _a, _b, _c, _d;
|
|
1537
|
+
if (!bodyStyles.current) {
|
|
1538
|
+
bodyStyles.current = css.css({
|
|
1539
|
+
label: 'ModalBodyOverrides_' + ((_b = (_a = p.id) === null || _a === void 0 ? void 0 : _a.replace(/\s+/, '')) !== null && _b !== void 0 ? _b : nanoid.nanoid()),
|
|
1540
|
+
overflow: 'hidden',
|
|
1541
|
+
paddingRight: `${useScrollbarSize()}px`
|
|
1542
|
+
});
|
|
1543
|
+
log('creating singleton bodyStyles', bodyStyles.current);
|
|
1544
|
+
}
|
|
1545
|
+
if (!fixedElementStyles.current) {
|
|
1546
|
+
fixedElementStyles.current = css.css({
|
|
1547
|
+
label: 'ModalElementOverrides_' + ((_d = (_c = p.id) === null || _c === void 0 ? void 0 : _c.replace(/\s+/, '')) !== null && _d !== void 0 ? _d : nanoid.nanoid()),
|
|
1548
|
+
paddingRight: `${useScrollbarSize()}px`
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
document.body.classList.add(bodyStyles.current);
|
|
1552
|
+
Array.from(document.querySelectorAll(`.${modalScrollFixClassName}`)).forEach(e => {
|
|
1553
|
+
e.classList.add(fixedElementStyles.current);
|
|
1554
|
+
});
|
|
1555
|
+
};
|
|
1556
|
+
const tryRemoveScrollStyles = () => {
|
|
1557
|
+
if (bodyStyles.current) {
|
|
1558
|
+
log('removing singleton', bodyStyles.current);
|
|
1559
|
+
document.body.classList.remove(bodyStyles.current);
|
|
1560
|
+
}
|
|
1561
|
+
if (fixedElementStyles.current) {
|
|
1562
|
+
Array.from(document.querySelectorAll(`.${modalScrollFixClassName}`)).forEach(e => {
|
|
1563
|
+
e.classList.remove(fixedElementStyles.current);
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
React.useEffect(() => {
|
|
1568
|
+
log('mounted');
|
|
1569
|
+
return () => {
|
|
1570
|
+
var _a;
|
|
1571
|
+
if (showing.current) {
|
|
1572
|
+
log(`un-mount in progress and this modal is showing. decrement the backdrop and try to remove singleton body styles.`);
|
|
1573
|
+
backdrop.setShow(false, (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal');
|
|
1574
|
+
log('backdrop.setShow', false);
|
|
1575
|
+
tryRemoveScrollStyles();
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
log(`un-mount in progress but this modal is not showing. do nothing with the backdrop.`);
|
|
1579
|
+
}
|
|
1580
|
+
log('un-mounted');
|
|
1581
|
+
};
|
|
1582
|
+
}, []);
|
|
1583
|
+
useBooleanChanged((show, previousShow) => {
|
|
1584
|
+
var _a;
|
|
1585
|
+
log('show changed', `${previousShow !== null && previousShow !== void 0 ? previousShow : 'undefined'} > ${show}`);
|
|
1586
|
+
backdrop.setShow(show, (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal');
|
|
1587
|
+
showing.current = show;
|
|
1588
|
+
log('backdrop.setShow', show);
|
|
1589
|
+
if (show) {
|
|
1590
|
+
log('this modal is showing. adding singleton bodyStyles', bodyStyles.current);
|
|
1591
|
+
addScrollStyles();
|
|
1592
|
+
}
|
|
1593
|
+
else {
|
|
1594
|
+
log('this modal is hiding. try removing singleton bodyStyles');
|
|
1595
|
+
tryRemoveScrollStyles();
|
|
1596
|
+
}
|
|
1597
|
+
}, p.show);
|
|
1598
|
+
React__default['default'].useLayoutEffect(() => {
|
|
1599
|
+
var _a;
|
|
1600
|
+
if (p.show === true) {
|
|
1601
|
+
const focusSelector = (_a = p.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
|
|
1602
|
+
// still need to wait for the next tick so the children are all rendered.
|
|
1603
|
+
setTimeout(() => {
|
|
1604
|
+
var _a;
|
|
1605
|
+
const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
|
|
1606
|
+
element === null || element === void 0 ? void 0 : element.focus();
|
|
1607
|
+
log('set focus', focusSelector);
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
}, [p.show]);
|
|
1611
|
+
const modalBodyStyles = css.css({
|
|
1612
|
+
maxHeight: p.scrollable ? undefined : '99vh',
|
|
1613
|
+
overflow: 'hidden',
|
|
1614
|
+
zIndex: theme.zIndexes.modal,
|
|
1615
|
+
cursor: 'default',
|
|
1616
|
+
margin: '1rem',
|
|
1617
|
+
backgroundColor: p.noBackground ? undefined : theme.colors.modalBg,
|
|
1618
|
+
border: p.noBackground ? undefined : theme.controls.border,
|
|
1619
|
+
boxShadow: p.noBackground ? undefined : theme.controls.boxShadow,
|
|
1620
|
+
maxWidth: (_c = p.maxWidth) !== null && _c !== void 0 ? _c : theme.breakpoints.tablet,
|
|
1621
|
+
minWidth: (_d = p.minWidth) !== null && _d !== void 0 ? _d : (hasHeader ? '250px' : undefined),
|
|
1622
|
+
opacity: p.show ? 1 : 0,
|
|
1623
|
+
fontSize: theme.fonts.size,
|
|
1624
|
+
fontFamily: theme.fonts.family,
|
|
1625
|
+
fontWeight: 'normal',
|
|
1626
|
+
'&:focus': {
|
|
1627
|
+
outline: 'none'
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
const modalHeaderStyles = css.cx(css.css({
|
|
1631
|
+
display: 'flex',
|
|
1632
|
+
justifyContent: 'space-between',
|
|
1633
|
+
alignItems: 'center',
|
|
1634
|
+
backgroundColor: theme.colors.header,
|
|
1635
|
+
padding: '1rem',
|
|
1636
|
+
color: theme.colors.headerFont
|
|
1637
|
+
}), p.headerClassName);
|
|
1638
|
+
const modalContainerStyles = css.css([{
|
|
1639
|
+
position: 'fixed',
|
|
1640
|
+
height: '100%',
|
|
1641
|
+
width: '100%',
|
|
1642
|
+
backgroundColor: "transparent",
|
|
1643
|
+
display: 'flex',
|
|
1644
|
+
justifyContent: 'center',
|
|
1645
|
+
alignItems: 'center',
|
|
1646
|
+
cursor: p.onClick ? 'pointer' : 'default'
|
|
1647
|
+
}, p.scrollable && {
|
|
1648
|
+
overflowY: 'auto',
|
|
1649
|
+
overflowX: 'hidden',
|
|
1650
|
+
alignItems: 'flex-start'
|
|
1651
|
+
}]);
|
|
1652
|
+
if (p.show) {
|
|
1653
|
+
const backdropContainer = document.getElementById(backdrop.portalId);
|
|
1654
|
+
if (backdropContainer) {
|
|
1655
|
+
return reactDom.createPortal((React__default['default'].createElement("div", { onClick: e => {
|
|
1656
|
+
e.stopPropagation();
|
|
1657
|
+
if (!mouseDownElement.current) {
|
|
1658
|
+
if (p.onClick) {
|
|
1659
|
+
log('backdropContainer onClick');
|
|
1660
|
+
p.onClick();
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
mouseDownElement.current = undefined;
|
|
1664
|
+
}, className: css.cx('modalContainer', modalContainerStyles) },
|
|
1665
|
+
React__default['default'].createElement("div", { id: p.id, ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
|
|
1666
|
+
mouseDownElement.current = e.target;
|
|
1667
|
+
e.stopPropagation();
|
|
1668
|
+
}, onMouseUp: e => {
|
|
1669
|
+
mouseDownElement.current = undefined;
|
|
1670
|
+
/*
|
|
1671
|
+
MouseDown and MouseUp stopPropagation was added to fix bugs while clicking within the modal.
|
|
1672
|
+
At least in the case of MouseUp, this breaks sliders and the handle grab logic appears to live on window.
|
|
1673
|
+
Turning this off now. Should not cause any issues for MouseUp unlike MouseDown.
|
|
1674
|
+
*/
|
|
1675
|
+
// e.stopPropagation()
|
|
1676
|
+
}, className: css.cx('modalBody', modalBodyStyles, p.className) },
|
|
1677
|
+
React__default['default'].createElement(TabLocker, null,
|
|
1678
|
+
hasHeader && (React__default['default'].createElement("header", { className: css.cx('modalHeader', modalHeaderStyles) },
|
|
1679
|
+
p.heading ? React__default['default'].createElement(Text, { className: css.css({
|
|
1680
|
+
margin: 0,
|
|
1681
|
+
flexGrow: 1
|
|
1682
|
+
}), tag: "h1", bold: true }, p.heading) : React__default['default'].createElement("span", null),
|
|
1683
|
+
p.closeButton && p.onClick ? React__default['default'].createElement(Button, { className: css.cx('modalCloseButton', css.css({
|
|
1684
|
+
color: theme.colors.headerFont,
|
|
1685
|
+
marginLeft: '1rem',
|
|
1686
|
+
backgroundColor: 'transparent'
|
|
1687
|
+
})), variant: "icon", onClick: p.onClick },
|
|
1688
|
+
React__default['default'].createElement(Icon, { id: "close" })) : React__default['default'].createElement("span", null))),
|
|
1689
|
+
p.children)))), backdropContainer);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return null;
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1694
1695
|
const ConfirmModal = (props) => {
|
|
1695
1696
|
const theme = useThemeSafely();
|
|
1696
1697
|
const modalStyle = css.css `
|