@mackin.com/styleguide 11.0.3 → 11.0.5
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 +60 -20
- package/index.esm.js +195 -52
- package/index.js +196 -51
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import * as React from 'react';
|
|
2
3
|
import React__default, { ReactNode } from 'react';
|
|
3
4
|
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
@@ -280,31 +281,34 @@ declare const InfoPanel: (props: {
|
|
|
280
281
|
tag?: InfoPanelTag;
|
|
281
282
|
}) => React.JSX.Element;
|
|
282
283
|
|
|
284
|
+
type InfoTipDefaultProps = {
|
|
285
|
+
type: 'Info';
|
|
286
|
+
};
|
|
287
|
+
type InfoTipModalProps = {
|
|
288
|
+
type: 'Modal';
|
|
289
|
+
heading: string;
|
|
290
|
+
__debug?: boolean;
|
|
291
|
+
};
|
|
283
292
|
interface InfoTipProps {
|
|
293
|
+
/** Required for ARIA wireup. */
|
|
294
|
+
id: string;
|
|
295
|
+
variant: InfoTipDefaultProps | InfoTipModalProps;
|
|
284
296
|
content?: string | JSX.Element;
|
|
285
297
|
disabled?: boolean;
|
|
286
298
|
onClick?: () => void;
|
|
287
299
|
tabIndex?: number;
|
|
288
300
|
loadOnHover?: () => Promise<void>;
|
|
289
301
|
onClose?: () => void;
|
|
290
|
-
/** Defaults to 'info'. */
|
|
291
|
-
variant?: 'info' | 'modal';
|
|
292
302
|
/** Defaults to nav color. */
|
|
293
303
|
bgColor?: string;
|
|
294
304
|
/** Defaults to nav font color. */
|
|
295
305
|
fontColor?: string;
|
|
296
|
-
/** For variant=modal only. The InfoTip will not render if `variant=modal` and this is missing. */
|
|
297
|
-
modalProps?: {
|
|
298
|
-
heading: string;
|
|
299
|
-
id: string;
|
|
300
|
-
__debug?: boolean;
|
|
301
|
-
};
|
|
302
306
|
/** Whether to move the popover on collision with the parent's bounds. Default is false. For variant=info only. */
|
|
303
307
|
reposition?: boolean;
|
|
304
308
|
/** Order of positions as the Popover colides with the window edge. The default order is ['right', 'top', 'left', 'bottom']. For variant=info only. */
|
|
305
309
|
positions?: ("bottom" | "left" | "right" | "top")[] | undefined;
|
|
306
310
|
}
|
|
307
|
-
declare const InfoTip: (props: InfoTipProps) => React.JSX.Element
|
|
311
|
+
declare const InfoTip: (props: InfoTipProps) => React.JSX.Element;
|
|
308
312
|
|
|
309
313
|
interface BaseInputProps extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
|
|
310
314
|
rightControl?: JSX.Element;
|
|
@@ -413,14 +417,16 @@ interface ModalProps {
|
|
|
413
417
|
minWidth?: string;
|
|
414
418
|
/** Use to override default heading styling. */
|
|
415
419
|
headerClassName?: string;
|
|
416
|
-
/**
|
|
417
|
-
|
|
420
|
+
/** The DOM ID of the element to focus on initial show. Will default to the close button. */
|
|
421
|
+
focusContentId?: string;
|
|
418
422
|
scrollable?: boolean;
|
|
419
423
|
/** Applied to the modal body. */
|
|
420
424
|
className?: string;
|
|
425
|
+
/** Applied to the close button. */
|
|
426
|
+
closeButtonClassName?: string;
|
|
421
427
|
__debug?: boolean;
|
|
422
428
|
/** Only used for the `WaitingIndicator`. This will break accessiblity so do not use. */
|
|
423
|
-
|
|
429
|
+
__asWaitingIndicator?: boolean;
|
|
424
430
|
onClose: () => void;
|
|
425
431
|
}
|
|
426
432
|
declare const Modal: (p: ModalProps) => React__default.ReactPortal | null;
|
|
@@ -428,7 +434,7 @@ declare const Modal: (p: ModalProps) => React__default.ReactPortal | null;
|
|
|
428
434
|
declare const Nav: (props: {
|
|
429
435
|
show: boolean;
|
|
430
436
|
/** Required for ARIA. The element to focus when first opened. */
|
|
431
|
-
|
|
437
|
+
focusContentId: string;
|
|
432
438
|
/** Required for ARIA. Description of the `Nav` purpose. */
|
|
433
439
|
ariaLabel: string;
|
|
434
440
|
toggle: (show: boolean) => void;
|
|
@@ -654,16 +660,18 @@ interface PickerProps<T extends PickerValue> extends SelectProps {
|
|
|
654
660
|
}
|
|
655
661
|
declare const Picker: <T extends PickerValue>(props: PickerProps<T>) => React.JSX.Element;
|
|
656
662
|
|
|
657
|
-
|
|
663
|
+
type PopoverPosition = "bottom" | "left" | "right" | "top";
|
|
664
|
+
|
|
665
|
+
type BasePopoverProps = {
|
|
658
666
|
isOpen: boolean;
|
|
659
667
|
/** The content inside the popover. */
|
|
660
668
|
content: JSX.Element;
|
|
661
669
|
/** The element controlling the state of the popover. */
|
|
662
670
|
parent: JSX.Element;
|
|
663
|
-
|
|
671
|
+
/** Will be called when the user pressed the `Escape` key or clicks outside of the popover. */
|
|
672
|
+
onClose: () => void;
|
|
664
673
|
/** Whether to move the popover on collision with the parent's bounds. Default is true. */
|
|
665
674
|
reposition?: boolean;
|
|
666
|
-
onClickOutside?: (e: MouseEvent) => void;
|
|
667
675
|
/** Popover arrow color. Defaults to theme.colors.border. */
|
|
668
676
|
arrorColor?: string;
|
|
669
677
|
/** Popover border. Defaults to theme.controls.border. */
|
|
@@ -671,11 +679,32 @@ interface PopoverProps {
|
|
|
671
679
|
/** Popover background. Defaults to theme.colors.bg. */
|
|
672
680
|
backgroundColor?: string;
|
|
673
681
|
/** Order of positions as the Popover colides with the window edge. The default order is ['right', 'top', 'left', 'bottom']. */
|
|
674
|
-
positions?:
|
|
682
|
+
positions?: PopoverPosition[] | undefined;
|
|
675
683
|
/** Targets the wrapper around `parent`. Use if you're having positioning issues when the tooltip is showing. */
|
|
676
684
|
parentWrapperClassName?: string;
|
|
677
|
-
}
|
|
678
|
-
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
type DialogPopoverProps = BasePopoverProps & {
|
|
688
|
+
/** The DOM ID of the parent element to return focus to after the popup closes. */
|
|
689
|
+
focusParentId: string;
|
|
690
|
+
/** The DOM ID of the element to focus when the popover opens. If there are no focusable elements, you'll need to
|
|
691
|
+
* add `tabindex="-1"` to something in `content` to comply with ARIA guidelines for dialogs.
|
|
692
|
+
*/
|
|
693
|
+
focusContentId: string;
|
|
694
|
+
/** For screen readers to read on show. */
|
|
695
|
+
ariaLabel: string;
|
|
696
|
+
/** DO NOT USE. Here only for legacy component support. */
|
|
697
|
+
__asDateInputCalendar?: boolean;
|
|
698
|
+
};
|
|
699
|
+
/** Use this popover for modal dialogs that stay up until dismissed by the user. Never use this for informational tooltips - use TooltipPopover for that instead. */
|
|
700
|
+
declare const DialogPopover: (p: DialogPopoverProps) => React.JSX.Element;
|
|
701
|
+
|
|
702
|
+
type TooltipPopoverProps = BasePopoverProps & {
|
|
703
|
+
/** Required for ARIA linking between elements. */
|
|
704
|
+
id: string;
|
|
705
|
+
};
|
|
706
|
+
/** Use this popover for tooltips that are shown and dimissed on hover. Never use this for modal tooltips - use DialogPopover for that instead. */
|
|
707
|
+
declare const TooltipPopover: (p: TooltipPopoverProps) => React.JSX.Element;
|
|
679
708
|
|
|
680
709
|
interface ProgressBarProps {
|
|
681
710
|
/** The value in whole pct - 55 NOT 0.55. */
|
|
@@ -1195,4 +1224,15 @@ declare const LocalizationProvider: (p: {
|
|
|
1195
1224
|
__debug?: boolean;
|
|
1196
1225
|
}) => React__default.JSX.Element;
|
|
1197
1226
|
|
|
1198
|
-
|
|
1227
|
+
/** Allows for status notificaiton methods for screen readers.
|
|
1228
|
+
* This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
|
|
1229
|
+
declare function useAriaLiveRegion(): {
|
|
1230
|
+
/**
|
|
1231
|
+
* @param message - The text to be read by the screen reader.
|
|
1232
|
+
* @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
|
|
1233
|
+
*/
|
|
1234
|
+
notify: (message: string, clearTimoutMs?: number) => void;
|
|
1235
|
+
clearNotification: () => void;
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
export { Accordian, type AccordianProps, type Alignment, Autocomplete, AutocompleteController, AutocompleteEntityController, type AutocompleteProps, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, type ButtonProps, Calendar, type CalendarProps, Checkbox, type CheckboxProps, ConfirmModal, type ConfirmModalProps, CopyButton, DateInput, type DateInputProps, DialogPopover, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, type FormProps, GlobalStyles, Header, Highlight, ICONS, Icon, Image, type ImageProps, InfoPanel, InfoTip, type InfoTipProps, ItemPager, Label, type LabelProps, Link, type LinkProps, List, ListItem, type ListItemProps, type ListProps, LocalizationProvider, type MackinTheme, Modal, type ModalProps, Nav, NormalizeCss, NumberInput, type NumberInputProps, OmniLink, type OmniLinkProps, PagedResult, type PagedResultDto, Pager, type PagerProps, Picker, type PickerOption, type PickerProps, type PickerValue, ProgressBar, type ProgressBarProps, SearchBox, type SearchBoxProps, Slider, type SliderProps, type SliderValue, StyleGuideLanguage, TabContainer, type TabContainerProps, TabHeader, type TabHeaderProps, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, type TextAreaProps, TextInput, type TextInputProps, type TextProps, Th, ThSort, ThemeProvider, ThemeRenderer, ToggleButton, ToggleButtonGroup, type ToggleButtonGroupProps, type ToggleButtonProps, TogglePasswordInput, TooltipPopover, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
|
package/index.esm.js
CHANGED
|
@@ -8,7 +8,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
8
8
|
import { uniqueId, sumBy, orderBy, get } from 'lodash';
|
|
9
9
|
import { format, getDaysInMonth, getDay, isSameMonth, isBefore, isAfter, isSameDay, endOfYear, addYears, endOfMonth, addMonths, startOfMonth, startOfYear, isExists } from 'date-fns';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
11
|
-
import { Popover
|
|
11
|
+
import { Popover, ArrowContainer } from 'react-tiny-popover';
|
|
12
12
|
import { Link as Link$1 } from 'react-router-dom';
|
|
13
13
|
import ReactSlider from 'react-slider';
|
|
14
14
|
|
|
@@ -1608,6 +1608,18 @@ const Checkbox = (props) => {
|
|
|
1608
1608
|
props.children)));
|
|
1609
1609
|
};
|
|
1610
1610
|
|
|
1611
|
+
function createBodyEscapeHandler(onEscape) {
|
|
1612
|
+
const handler = (e) => {
|
|
1613
|
+
if (e.code === 'Escape') {
|
|
1614
|
+
onEscape();
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
document.addEventListener('keydown', handler);
|
|
1618
|
+
return () => {
|
|
1619
|
+
document.removeEventListener('keydown', handler);
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1611
1623
|
/** useEffect but it will only fire when the actual truthiness of the value changes.
|
|
1612
1624
|
* Use for comparing previous states to next states without all the bullshit around useEffect and component mounting.
|
|
1613
1625
|
*/
|
|
@@ -1663,12 +1675,13 @@ const Modal = (p) => {
|
|
|
1663
1675
|
const backdrop = useBackdropContext();
|
|
1664
1676
|
const mouseDownElement = useRef(undefined);
|
|
1665
1677
|
const theme = useThemeSafely();
|
|
1666
|
-
const hasHeader = !p.
|
|
1678
|
+
const hasHeader = !p.__asWaitingIndicator;
|
|
1667
1679
|
const contentRef = React__default.useRef(null);
|
|
1668
1680
|
const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
1669
1681
|
const showing = useRef(p.show);
|
|
1670
1682
|
const bodyStyles = useRef('');
|
|
1671
1683
|
const fixedElementStyles = useRef('');
|
|
1684
|
+
const closeButtonId = `${p.id}_closeButton`;
|
|
1672
1685
|
const addScrollStyles = () => {
|
|
1673
1686
|
var _a, _b, _c, _d;
|
|
1674
1687
|
if (!bodyStyles.current) {
|
|
@@ -1748,13 +1761,12 @@ const Modal = (p) => {
|
|
|
1748
1761
|
React__default.useLayoutEffect(() => {
|
|
1749
1762
|
var _a;
|
|
1750
1763
|
if (p.show === true) {
|
|
1751
|
-
const
|
|
1764
|
+
const focusId = (_a = p.focusContentId) !== null && _a !== void 0 ? _a : closeButtonId;
|
|
1752
1765
|
// still need to wait for the next tick so the children are all rendered.
|
|
1753
1766
|
setTimeout(() => {
|
|
1754
|
-
|
|
1755
|
-
const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
|
|
1767
|
+
const element = document.getElementById(focusId);
|
|
1756
1768
|
element === null || element === void 0 ? void 0 : element.focus();
|
|
1757
|
-
log('set focus',
|
|
1769
|
+
log('set focus', focusId);
|
|
1758
1770
|
});
|
|
1759
1771
|
}
|
|
1760
1772
|
}, [p.show]);
|
|
@@ -1803,7 +1815,7 @@ const Modal = (p) => {
|
|
|
1803
1815
|
if (p.show) {
|
|
1804
1816
|
const backdropContainer = document.getElementById(backdrop.portalId);
|
|
1805
1817
|
if (backdropContainer) {
|
|
1806
|
-
return createPortal((React__default.createElement("div", { id: p.id, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
|
|
1818
|
+
return createPortal((React__default.createElement("div", { id: p.id, "aria-hidden": p.__asWaitingIndicator, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
|
|
1807
1819
|
e.stopPropagation();
|
|
1808
1820
|
if (!mouseDownElement.current) {
|
|
1809
1821
|
log('backdropContainer onClick');
|
|
@@ -1834,11 +1846,11 @@ const Modal = (p) => {
|
|
|
1834
1846
|
margin: 0,
|
|
1835
1847
|
flexGrow: 1
|
|
1836
1848
|
}), tag: "h1", bold: true }, p.heading),
|
|
1837
|
-
React__default.createElement(Button, { className: cx('modalCloseButton', css({
|
|
1849
|
+
React__default.createElement(Button, { id: closeButtonId, className: cx('modalCloseButton', css({
|
|
1838
1850
|
color: theme.colors.headerFont,
|
|
1839
1851
|
marginLeft: '1rem',
|
|
1840
1852
|
backgroundColor: 'transparent'
|
|
1841
|
-
})), "aria-label": closeText, variant: "icon", onClick: e => {
|
|
1853
|
+
}), p.closeButtonClassName), "aria-label": closeText, variant: "icon", onClick: e => {
|
|
1842
1854
|
e.stopPropagation();
|
|
1843
1855
|
p.onClose();
|
|
1844
1856
|
} },
|
|
@@ -1848,17 +1860,6 @@ const Modal = (p) => {
|
|
|
1848
1860
|
}
|
|
1849
1861
|
return null;
|
|
1850
1862
|
};
|
|
1851
|
-
function createBodyEscapeHandler(onEscape) {
|
|
1852
|
-
const handler = (e) => {
|
|
1853
|
-
if (e.code === 'Escape') {
|
|
1854
|
-
onEscape();
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1857
|
-
document.addEventListener('keydown', handler);
|
|
1858
|
-
return () => {
|
|
1859
|
-
document.removeEventListener('keydown', handler);
|
|
1860
|
-
};
|
|
1861
|
-
}
|
|
1862
1863
|
|
|
1863
1864
|
const ConfirmModal = (props) => {
|
|
1864
1865
|
const theme = useThemeSafely();
|
|
@@ -2388,34 +2389,60 @@ const Image = React.forwardRef((p, ref) => {
|
|
|
2388
2389
|
}), p.className) })));
|
|
2389
2390
|
});
|
|
2390
2391
|
|
|
2391
|
-
|
|
2392
|
-
|
|
2392
|
+
function getPopoverContainerClass(theme) {
|
|
2393
|
+
return css({
|
|
2394
|
+
label: 'PopoverContainer',
|
|
2395
|
+
zIndex: theme.zIndexes.tooltip
|
|
2396
|
+
});
|
|
2397
|
+
}
|
|
2398
|
+
function getPopoverContentWrapperClass(theme, props) {
|
|
2399
|
+
var _a, _b, _c;
|
|
2400
|
+
return css({
|
|
2401
|
+
label: 'PopoverContentWrapper',
|
|
2402
|
+
border: (_a = props.border) !== null && _a !== void 0 ? _a : theme.controls.border,
|
|
2403
|
+
borderRadius: (_b = props.border) !== null && _b !== void 0 ? _b : theme.controls.borderRadius,
|
|
2404
|
+
boxShadow: theme.controls.boxShadow,
|
|
2405
|
+
backgroundColor: (_c = props.backgroundColor) !== null && _c !== void 0 ? _c : theme.colors.bg,
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
function getPopoverArrowColor(theme, props) {
|
|
2409
|
+
var _a;
|
|
2410
|
+
return (_a = props.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border;
|
|
2411
|
+
}
|
|
2412
|
+
function getPopoverPositions(props) {
|
|
2413
|
+
var _a;
|
|
2414
|
+
return (_a = props.positions) !== null && _a !== void 0 ? _a : ['right', 'top', 'left', 'bottom'];
|
|
2415
|
+
}
|
|
2416
|
+
const popoverArrowSize = 10;
|
|
2417
|
+
|
|
2418
|
+
/** Use this popover for tooltips that are shown and dimissed on hover. Never use this for modal tooltips - use DialogPopover for that instead. */
|
|
2419
|
+
const TooltipPopover = (p) => {
|
|
2420
|
+
var _a;
|
|
2393
2421
|
const theme = useThemeSafely();
|
|
2394
2422
|
const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2423
|
+
React.useEffect(() => {
|
|
2424
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2425
|
+
if (p.isOpen) {
|
|
2426
|
+
p.onClose();
|
|
2427
|
+
}
|
|
2428
|
+
});
|
|
2429
|
+
return escapeRemover;
|
|
2430
|
+
}, [p.isOpen]);
|
|
2431
|
+
return (React.createElement(Popover, { containerClassName: getPopoverContainerClass(theme), reposition: resposition, isOpen: p.isOpen, positions: getPopoverPositions(p), onClickOutside: p.onClose, content: ({ position, childRect, popoverRect }) => (React.createElement(ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: getPopoverArrowColor(theme, p), arrowSize: popoverArrowSize },
|
|
2432
|
+
React.createElement("div", { id: p.id, onKeyDown: e => {
|
|
2433
|
+
if (e.code === 'Escape') {
|
|
2434
|
+
e.stopPropagation();
|
|
2435
|
+
e.preventDefault();
|
|
2436
|
+
p.onClose();
|
|
2437
|
+
}
|
|
2438
|
+
}, role: 'tooltip', className: getPopoverContentWrapperClass(theme, p) }, p.content))) },
|
|
2439
|
+
React.createElement("span", { "aria-describedby": p.id, className: p.parentWrapperClassName }, p.parent)));
|
|
2409
2440
|
};
|
|
2410
2441
|
|
|
2411
2442
|
const InfoTip = (props) => {
|
|
2412
2443
|
var _a, _b, _c;
|
|
2413
2444
|
const [showTip, setShowTip] = React.useState(false);
|
|
2414
2445
|
const theme = useThemeSafely();
|
|
2415
|
-
if (props.variant === 'modal' && !props.modalProps) {
|
|
2416
|
-
console.warn(`InfoTip with variant=modal requires modalProps.`);
|
|
2417
|
-
return null;
|
|
2418
|
-
}
|
|
2419
2446
|
const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
|
|
2420
2447
|
const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
|
|
2421
2448
|
const onClick = () => {
|
|
@@ -2427,7 +2454,7 @@ const InfoTip = (props) => {
|
|
|
2427
2454
|
}
|
|
2428
2455
|
};
|
|
2429
2456
|
const onMouseOver = () => {
|
|
2430
|
-
if (props.variant === '
|
|
2457
|
+
if (props.variant.type === 'Modal') {
|
|
2431
2458
|
return;
|
|
2432
2459
|
}
|
|
2433
2460
|
if (props.loadOnHover) {
|
|
@@ -2442,7 +2469,7 @@ const InfoTip = (props) => {
|
|
|
2442
2469
|
}
|
|
2443
2470
|
};
|
|
2444
2471
|
const onMouseOut = () => {
|
|
2445
|
-
if (props.variant === '
|
|
2472
|
+
if (props.variant.type === 'Modal') {
|
|
2446
2473
|
return;
|
|
2447
2474
|
}
|
|
2448
2475
|
closeTip();
|
|
@@ -2471,17 +2498,22 @@ const InfoTip = (props) => {
|
|
|
2471
2498
|
font-family: serif;
|
|
2472
2499
|
display:inline-block;
|
|
2473
2500
|
`;
|
|
2474
|
-
|
|
2475
|
-
|
|
2501
|
+
let onButtonBlur = props.variant.type === 'Info' ?
|
|
2502
|
+
() => {
|
|
2503
|
+
closeTip();
|
|
2504
|
+
} :
|
|
2505
|
+
undefined;
|
|
2506
|
+
const button = (React.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut, onBlur: onButtonBlur }, "i"));
|
|
2507
|
+
if (props.variant.type === 'Modal') {
|
|
2476
2508
|
return (React.createElement(React.Fragment, null,
|
|
2477
2509
|
button,
|
|
2478
|
-
React.createElement(Modal, { id: props.
|
|
2510
|
+
React.createElement(Modal, { id: props.id, __debug: props.variant.__debug, show: showTip, heading: props.variant.heading, onClose: closeTip, className: css({
|
|
2479
2511
|
whiteSpace: 'normal'
|
|
2480
2512
|
}) },
|
|
2481
2513
|
React.createElement("div", { className: css({ padding: '1rem' }) }, props.content))));
|
|
2482
2514
|
}
|
|
2483
2515
|
else {
|
|
2484
|
-
return (React.createElement(
|
|
2516
|
+
return (React.createElement(TooltipPopover, { id: props.id, positions: props.positions, reposition: (_c = props.reposition) !== null && _c !== void 0 ? _c : false, isOpen: showTip, onClose: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (React.createElement("div", { className: css({
|
|
2485
2517
|
padding: '0.5rem',
|
|
2486
2518
|
fontSize: '0.75rem',
|
|
2487
2519
|
maxWidth: '22rem'
|
|
@@ -2489,6 +2521,47 @@ const InfoTip = (props) => {
|
|
|
2489
2521
|
}
|
|
2490
2522
|
};
|
|
2491
2523
|
|
|
2524
|
+
/** Use this popover for modal dialogs that stay up until dismissed by the user. Never use this for informational tooltips - use TooltipPopover for that instead. */
|
|
2525
|
+
const DialogPopover = (p) => {
|
|
2526
|
+
var _a;
|
|
2527
|
+
const theme = useThemeSafely();
|
|
2528
|
+
const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
|
|
2529
|
+
React.useEffect(() => {
|
|
2530
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2531
|
+
if (p.isOpen) {
|
|
2532
|
+
p.onClose();
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
return escapeRemover;
|
|
2536
|
+
}, [p.isOpen]);
|
|
2537
|
+
useIgnoreMount(() => {
|
|
2538
|
+
if (!p.__asDateInputCalendar) {
|
|
2539
|
+
if (p.isOpen) {
|
|
2540
|
+
const content = document.getElementById(p.focusContentId);
|
|
2541
|
+
if (content) {
|
|
2542
|
+
content.focus();
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
const parent = document.getElementById(p.focusParentId);
|
|
2547
|
+
if (parent) {
|
|
2548
|
+
parent.focus();
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}, [p.isOpen]);
|
|
2553
|
+
return (React.createElement(Popover, { containerClassName: getPopoverContainerClass(theme), reposition: resposition, isOpen: p.isOpen, positions: getPopoverPositions(p), onClickOutside: p.onClose, content: ({ position, childRect, popoverRect }) => (React.createElement(ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: getPopoverArrowColor(theme, p), arrowSize: popoverArrowSize },
|
|
2554
|
+
React.createElement(TabLocker, null,
|
|
2555
|
+
React.createElement("div", { onKeyDown: e => {
|
|
2556
|
+
if (e.code === 'Escape') {
|
|
2557
|
+
e.stopPropagation();
|
|
2558
|
+
e.preventDefault();
|
|
2559
|
+
p.onClose();
|
|
2560
|
+
}
|
|
2561
|
+
}, role: 'dialog', "aria-modal": true, "aria-label": p.ariaLabel, className: getPopoverContentWrapperClass(theme, p) }, p.content)))) },
|
|
2562
|
+
React.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
|
|
2563
|
+
};
|
|
2564
|
+
|
|
2492
2565
|
const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
|
|
2493
2566
|
const datePattern = dateRegex.source;
|
|
2494
2567
|
const invalidDateMessage = 'Invalid date.';
|
|
@@ -2618,9 +2691,16 @@ const DateInput = React.forwardRef((props, ref) => {
|
|
|
2618
2691
|
}
|
|
2619
2692
|
(_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
|
|
2620
2693
|
} })));
|
|
2621
|
-
return (React.createElement(
|
|
2694
|
+
return (React.createElement(DialogPopover, { ariaLabel: 'Calendar',
|
|
2695
|
+
// Focus is handled here so we're opting out of the popover behavior in the most hackish way.
|
|
2696
|
+
// When there's time, remove the logic from here that now exists in the DialogPopover.
|
|
2697
|
+
focusContentId: '', focusParentId: '', __asDateInputCalendar: true, onClose: () => {
|
|
2622
2698
|
toggleCalendar(false);
|
|
2623
|
-
},
|
|
2699
|
+
},
|
|
2700
|
+
// above two lines are required due to ARIA changes.
|
|
2701
|
+
// we don't need to re-do this component since it already manages it's own focus in a very
|
|
2702
|
+
// complicated way
|
|
2703
|
+
reposition: reposition, isOpen: showCalendar, parent: input, content: (React.createElement("div", { ref: popover, className: css({
|
|
2624
2704
|
paddingLeft: '1rem',
|
|
2625
2705
|
paddingRight: '1rem',
|
|
2626
2706
|
paddingBottom: '1rem'
|
|
@@ -2899,7 +2979,7 @@ const Nav = (props) => {
|
|
|
2899
2979
|
nav.current.classList.add(classNavShowing);
|
|
2900
2980
|
setTimeout(() => {
|
|
2901
2981
|
var _a;
|
|
2902
|
-
(_a = document.
|
|
2982
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2903
2983
|
}, slideMs + 1);
|
|
2904
2984
|
}
|
|
2905
2985
|
}
|
|
@@ -4508,12 +4588,68 @@ const TogglePasswordInput = React.forwardRef((props, ref) => {
|
|
|
4508
4588
|
React.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4509
4589
|
});
|
|
4510
4590
|
|
|
4591
|
+
let clearTimerId = undefined;
|
|
4592
|
+
/** Allows for status notificaiton methods for screen readers.
|
|
4593
|
+
* This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
|
|
4594
|
+
function useAriaLiveRegion() {
|
|
4595
|
+
const id = 'MknAriaLiveRegion';
|
|
4596
|
+
if (!document.getElementById(id)) {
|
|
4597
|
+
const div = document.createElement('div');
|
|
4598
|
+
div.id = id;
|
|
4599
|
+
// different sources cannot decide if this is needed.
|
|
4600
|
+
// "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
|
|
4601
|
+
div.role = 'status';
|
|
4602
|
+
div.ariaLive = 'polite';
|
|
4603
|
+
div.ariaAtomic = 'true';
|
|
4604
|
+
div.style.position = 'absolute';
|
|
4605
|
+
div.style.width = '1px';
|
|
4606
|
+
div.style.height = '1px';
|
|
4607
|
+
div.style.padding = '0px';
|
|
4608
|
+
div.style.margin = '-1px';
|
|
4609
|
+
div.style.overflow = 'hidden';
|
|
4610
|
+
div.style.whiteSpace = 'nowrap';
|
|
4611
|
+
document.body.prepend(div);
|
|
4612
|
+
}
|
|
4613
|
+
const clearNotification = () => {
|
|
4614
|
+
if (clearTimerId) {
|
|
4615
|
+
clearTimeout(clearTimerId);
|
|
4616
|
+
}
|
|
4617
|
+
const element = document.getElementById(id);
|
|
4618
|
+
if (!element) {
|
|
4619
|
+
return;
|
|
4620
|
+
}
|
|
4621
|
+
element.textContent = '';
|
|
4622
|
+
};
|
|
4623
|
+
return {
|
|
4624
|
+
/**
|
|
4625
|
+
* @param message - The text to be read by the screen reader.
|
|
4626
|
+
* @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
|
|
4627
|
+
*/
|
|
4628
|
+
notify: (message, clearTimoutMs) => {
|
|
4629
|
+
if (clearTimerId) {
|
|
4630
|
+
clearTimeout(clearTimerId);
|
|
4631
|
+
}
|
|
4632
|
+
const element = document.getElementById(id);
|
|
4633
|
+
if (!element) {
|
|
4634
|
+
return;
|
|
4635
|
+
}
|
|
4636
|
+
element.textContent = message;
|
|
4637
|
+
clearTimerId = setTimeout(() => {
|
|
4638
|
+
// this is considered a good practice. if you leave text here, some screen readers will read it out randomly as you navigate around the page.
|
|
4639
|
+
clearNotification();
|
|
4640
|
+
}, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
|
|
4641
|
+
},
|
|
4642
|
+
clearNotification
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4511
4646
|
const WaitingIndicator = (p) => {
|
|
4512
4647
|
var _a, _b, _c;
|
|
4513
4648
|
const [show, setShow] = useState(p.show);
|
|
4514
4649
|
const hideTimer = useRef(0);
|
|
4515
4650
|
const lastShowStatus = useRef(false);
|
|
4516
4651
|
const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
4652
|
+
const { notify, clearNotification } = useAriaLiveRegion();
|
|
4517
4653
|
if (p.__debug) {
|
|
4518
4654
|
useEffect(() => {
|
|
4519
4655
|
log('mounted');
|
|
@@ -4560,9 +4696,16 @@ const WaitingIndicator = (p) => {
|
|
|
4560
4696
|
log('ignoring show change due to hideTimer ticking');
|
|
4561
4697
|
}
|
|
4562
4698
|
}
|
|
4699
|
+
if (p.show) {
|
|
4700
|
+
// set to a very long time so the hiding of the waiting indicator clears it.
|
|
4701
|
+
notify('Loading content.', 60000);
|
|
4702
|
+
}
|
|
4703
|
+
else {
|
|
4704
|
+
clearNotification();
|
|
4705
|
+
}
|
|
4563
4706
|
}, [p.show]);
|
|
4564
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4565
|
-
return (React__default.createElement(Modal, { id: id, __debug: p.__debug,
|
|
4707
|
+
const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
|
|
4708
|
+
return (React__default.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
|
|
4566
4709
|
/* noop */
|
|
4567
4710
|
}, className: "waitingIndicator", show: show },
|
|
4568
4711
|
React__default.createElement("div", { className: css({
|
|
@@ -5148,5 +5291,5 @@ const LocalizationProvider = (p) => {
|
|
|
5148
5291
|
} }, p.children));
|
|
5149
5292
|
};
|
|
5150
5293
|
|
|
5151
|
-
export { Accordian, Autocomplete, AutocompleteController, AutocompleteEntityController, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, Calendar, Checkbox, ConfirmModal, CopyButton, DateInput, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, ItemPager, Label, Link, List, ListItem, LocalizationProvider, Modal, Nav, NormalizeCss, NumberInput, OmniLink, PagedResult, Pager, Picker,
|
|
5294
|
+
export { Accordian, Autocomplete, AutocompleteController, AutocompleteEntityController, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, Calendar, Checkbox, ConfirmModal, CopyButton, DateInput, DialogPopover, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, ItemPager, Label, Link, List, ListItem, LocalizationProvider, Modal, Nav, NormalizeCss, NumberInput, OmniLink, PagedResult, Pager, Picker, ProgressBar, SearchBox, Slider, StyleGuideLanguage, TabContainer, TabHeader, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, TextInput, Th, ThSort, ThemeProvider, ThemeRenderer, ToggleButton, ToggleButtonGroup, TogglePasswordInput, TooltipPopover, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
|
|
5152
5295
|
//# sourceMappingURL=index.esm.js.map
|
package/index.js
CHANGED
|
@@ -1626,6 +1626,18 @@ const Checkbox = (props) => {
|
|
|
1626
1626
|
props.children)));
|
|
1627
1627
|
};
|
|
1628
1628
|
|
|
1629
|
+
function createBodyEscapeHandler(onEscape) {
|
|
1630
|
+
const handler = (e) => {
|
|
1631
|
+
if (e.code === 'Escape') {
|
|
1632
|
+
onEscape();
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
document.addEventListener('keydown', handler);
|
|
1636
|
+
return () => {
|
|
1637
|
+
document.removeEventListener('keydown', handler);
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1629
1641
|
/** useEffect but it will only fire when the actual truthiness of the value changes.
|
|
1630
1642
|
* Use for comparing previous states to next states without all the bullshit around useEffect and component mounting.
|
|
1631
1643
|
*/
|
|
@@ -1681,12 +1693,13 @@ const Modal = (p) => {
|
|
|
1681
1693
|
const backdrop = useBackdropContext();
|
|
1682
1694
|
const mouseDownElement = React.useRef(undefined);
|
|
1683
1695
|
const theme = useThemeSafely();
|
|
1684
|
-
const hasHeader = !p.
|
|
1696
|
+
const hasHeader = !p.__asWaitingIndicator;
|
|
1685
1697
|
const contentRef = React.useRef(null);
|
|
1686
1698
|
const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
1687
1699
|
const showing = React.useRef(p.show);
|
|
1688
1700
|
const bodyStyles = React.useRef('');
|
|
1689
1701
|
const fixedElementStyles = React.useRef('');
|
|
1702
|
+
const closeButtonId = `${p.id}_closeButton`;
|
|
1690
1703
|
const addScrollStyles = () => {
|
|
1691
1704
|
var _a, _b, _c, _d;
|
|
1692
1705
|
if (!bodyStyles.current) {
|
|
@@ -1766,13 +1779,12 @@ const Modal = (p) => {
|
|
|
1766
1779
|
React.useLayoutEffect(() => {
|
|
1767
1780
|
var _a;
|
|
1768
1781
|
if (p.show === true) {
|
|
1769
|
-
const
|
|
1782
|
+
const focusId = (_a = p.focusContentId) !== null && _a !== void 0 ? _a : closeButtonId;
|
|
1770
1783
|
// still need to wait for the next tick so the children are all rendered.
|
|
1771
1784
|
setTimeout(() => {
|
|
1772
|
-
|
|
1773
|
-
const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
|
|
1785
|
+
const element = document.getElementById(focusId);
|
|
1774
1786
|
element === null || element === void 0 ? void 0 : element.focus();
|
|
1775
|
-
log('set focus',
|
|
1787
|
+
log('set focus', focusId);
|
|
1776
1788
|
});
|
|
1777
1789
|
}
|
|
1778
1790
|
}, [p.show]);
|
|
@@ -1821,7 +1833,7 @@ const Modal = (p) => {
|
|
|
1821
1833
|
if (p.show) {
|
|
1822
1834
|
const backdropContainer = document.getElementById(backdrop.portalId);
|
|
1823
1835
|
if (backdropContainer) {
|
|
1824
|
-
return reactDom.createPortal((React.createElement("div", { id: p.id, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
|
|
1836
|
+
return reactDom.createPortal((React.createElement("div", { id: p.id, "aria-hidden": p.__asWaitingIndicator, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
|
|
1825
1837
|
e.stopPropagation();
|
|
1826
1838
|
if (!mouseDownElement.current) {
|
|
1827
1839
|
log('backdropContainer onClick');
|
|
@@ -1852,11 +1864,11 @@ const Modal = (p) => {
|
|
|
1852
1864
|
margin: 0,
|
|
1853
1865
|
flexGrow: 1
|
|
1854
1866
|
}), tag: "h1", bold: true }, p.heading),
|
|
1855
|
-
React.createElement(Button, { className: css.cx('modalCloseButton', css.css({
|
|
1867
|
+
React.createElement(Button, { id: closeButtonId, className: css.cx('modalCloseButton', css.css({
|
|
1856
1868
|
color: theme.colors.headerFont,
|
|
1857
1869
|
marginLeft: '1rem',
|
|
1858
1870
|
backgroundColor: 'transparent'
|
|
1859
|
-
})), "aria-label": closeText, variant: "icon", onClick: e => {
|
|
1871
|
+
}), p.closeButtonClassName), "aria-label": closeText, variant: "icon", onClick: e => {
|
|
1860
1872
|
e.stopPropagation();
|
|
1861
1873
|
p.onClose();
|
|
1862
1874
|
} },
|
|
@@ -1866,17 +1878,6 @@ const Modal = (p) => {
|
|
|
1866
1878
|
}
|
|
1867
1879
|
return null;
|
|
1868
1880
|
};
|
|
1869
|
-
function createBodyEscapeHandler(onEscape) {
|
|
1870
|
-
const handler = (e) => {
|
|
1871
|
-
if (e.code === 'Escape') {
|
|
1872
|
-
onEscape();
|
|
1873
|
-
}
|
|
1874
|
-
};
|
|
1875
|
-
document.addEventListener('keydown', handler);
|
|
1876
|
-
return () => {
|
|
1877
|
-
document.removeEventListener('keydown', handler);
|
|
1878
|
-
};
|
|
1879
|
-
}
|
|
1880
1881
|
|
|
1881
1882
|
const ConfirmModal = (props) => {
|
|
1882
1883
|
const theme = useThemeSafely();
|
|
@@ -2406,34 +2407,60 @@ const Image = React__namespace.forwardRef((p, ref) => {
|
|
|
2406
2407
|
}), p.className) })));
|
|
2407
2408
|
});
|
|
2408
2409
|
|
|
2409
|
-
|
|
2410
|
-
|
|
2410
|
+
function getPopoverContainerClass(theme) {
|
|
2411
|
+
return css.css({
|
|
2412
|
+
label: 'PopoverContainer',
|
|
2413
|
+
zIndex: theme.zIndexes.tooltip
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
function getPopoverContentWrapperClass(theme, props) {
|
|
2417
|
+
var _a, _b, _c;
|
|
2418
|
+
return css.css({
|
|
2419
|
+
label: 'PopoverContentWrapper',
|
|
2420
|
+
border: (_a = props.border) !== null && _a !== void 0 ? _a : theme.controls.border,
|
|
2421
|
+
borderRadius: (_b = props.border) !== null && _b !== void 0 ? _b : theme.controls.borderRadius,
|
|
2422
|
+
boxShadow: theme.controls.boxShadow,
|
|
2423
|
+
backgroundColor: (_c = props.backgroundColor) !== null && _c !== void 0 ? _c : theme.colors.bg,
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
function getPopoverArrowColor(theme, props) {
|
|
2427
|
+
var _a;
|
|
2428
|
+
return (_a = props.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border;
|
|
2429
|
+
}
|
|
2430
|
+
function getPopoverPositions(props) {
|
|
2431
|
+
var _a;
|
|
2432
|
+
return (_a = props.positions) !== null && _a !== void 0 ? _a : ['right', 'top', 'left', 'bottom'];
|
|
2433
|
+
}
|
|
2434
|
+
const popoverArrowSize = 10;
|
|
2435
|
+
|
|
2436
|
+
/** Use this popover for tooltips that are shown and dimissed on hover. Never use this for modal tooltips - use DialogPopover for that instead. */
|
|
2437
|
+
const TooltipPopover = (p) => {
|
|
2438
|
+
var _a;
|
|
2411
2439
|
const theme = useThemeSafely();
|
|
2412
2440
|
const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2441
|
+
React__namespace.useEffect(() => {
|
|
2442
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2443
|
+
if (p.isOpen) {
|
|
2444
|
+
p.onClose();
|
|
2445
|
+
}
|
|
2446
|
+
});
|
|
2447
|
+
return escapeRemover;
|
|
2448
|
+
}, [p.isOpen]);
|
|
2449
|
+
return (React__namespace.createElement(reactTinyPopover.Popover, { containerClassName: getPopoverContainerClass(theme), reposition: resposition, isOpen: p.isOpen, positions: getPopoverPositions(p), onClickOutside: p.onClose, content: ({ position, childRect, popoverRect }) => (React__namespace.createElement(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: getPopoverArrowColor(theme, p), arrowSize: popoverArrowSize },
|
|
2450
|
+
React__namespace.createElement("div", { id: p.id, onKeyDown: e => {
|
|
2451
|
+
if (e.code === 'Escape') {
|
|
2452
|
+
e.stopPropagation();
|
|
2453
|
+
e.preventDefault();
|
|
2454
|
+
p.onClose();
|
|
2455
|
+
}
|
|
2456
|
+
}, role: 'tooltip', className: getPopoverContentWrapperClass(theme, p) }, p.content))) },
|
|
2457
|
+
React__namespace.createElement("span", { "aria-describedby": p.id, className: p.parentWrapperClassName }, p.parent)));
|
|
2427
2458
|
};
|
|
2428
2459
|
|
|
2429
2460
|
const InfoTip = (props) => {
|
|
2430
2461
|
var _a, _b, _c;
|
|
2431
2462
|
const [showTip, setShowTip] = React__namespace.useState(false);
|
|
2432
2463
|
const theme = useThemeSafely();
|
|
2433
|
-
if (props.variant === 'modal' && !props.modalProps) {
|
|
2434
|
-
console.warn(`InfoTip with variant=modal requires modalProps.`);
|
|
2435
|
-
return null;
|
|
2436
|
-
}
|
|
2437
2464
|
const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
|
|
2438
2465
|
const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
|
|
2439
2466
|
const onClick = () => {
|
|
@@ -2445,7 +2472,7 @@ const InfoTip = (props) => {
|
|
|
2445
2472
|
}
|
|
2446
2473
|
};
|
|
2447
2474
|
const onMouseOver = () => {
|
|
2448
|
-
if (props.variant === '
|
|
2475
|
+
if (props.variant.type === 'Modal') {
|
|
2449
2476
|
return;
|
|
2450
2477
|
}
|
|
2451
2478
|
if (props.loadOnHover) {
|
|
@@ -2460,7 +2487,7 @@ const InfoTip = (props) => {
|
|
|
2460
2487
|
}
|
|
2461
2488
|
};
|
|
2462
2489
|
const onMouseOut = () => {
|
|
2463
|
-
if (props.variant === '
|
|
2490
|
+
if (props.variant.type === 'Modal') {
|
|
2464
2491
|
return;
|
|
2465
2492
|
}
|
|
2466
2493
|
closeTip();
|
|
@@ -2489,17 +2516,22 @@ const InfoTip = (props) => {
|
|
|
2489
2516
|
font-family: serif;
|
|
2490
2517
|
display:inline-block;
|
|
2491
2518
|
`;
|
|
2492
|
-
|
|
2493
|
-
|
|
2519
|
+
let onButtonBlur = props.variant.type === 'Info' ?
|
|
2520
|
+
() => {
|
|
2521
|
+
closeTip();
|
|
2522
|
+
} :
|
|
2523
|
+
undefined;
|
|
2524
|
+
const button = (React__namespace.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut, onBlur: onButtonBlur }, "i"));
|
|
2525
|
+
if (props.variant.type === 'Modal') {
|
|
2494
2526
|
return (React__namespace.createElement(React__namespace.Fragment, null,
|
|
2495
2527
|
button,
|
|
2496
|
-
React__namespace.createElement(Modal, { id: props.
|
|
2528
|
+
React__namespace.createElement(Modal, { id: props.id, __debug: props.variant.__debug, show: showTip, heading: props.variant.heading, onClose: closeTip, className: css.css({
|
|
2497
2529
|
whiteSpace: 'normal'
|
|
2498
2530
|
}) },
|
|
2499
2531
|
React__namespace.createElement("div", { className: css.css({ padding: '1rem' }) }, props.content))));
|
|
2500
2532
|
}
|
|
2501
2533
|
else {
|
|
2502
|
-
return (React__namespace.createElement(
|
|
2534
|
+
return (React__namespace.createElement(TooltipPopover, { id: props.id, positions: props.positions, reposition: (_c = props.reposition) !== null && _c !== void 0 ? _c : false, isOpen: showTip, onClose: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (React__namespace.createElement("div", { className: css.css({
|
|
2503
2535
|
padding: '0.5rem',
|
|
2504
2536
|
fontSize: '0.75rem',
|
|
2505
2537
|
maxWidth: '22rem'
|
|
@@ -2507,6 +2539,47 @@ const InfoTip = (props) => {
|
|
|
2507
2539
|
}
|
|
2508
2540
|
};
|
|
2509
2541
|
|
|
2542
|
+
/** Use this popover for modal dialogs that stay up until dismissed by the user. Never use this for informational tooltips - use TooltipPopover for that instead. */
|
|
2543
|
+
const DialogPopover = (p) => {
|
|
2544
|
+
var _a;
|
|
2545
|
+
const theme = useThemeSafely();
|
|
2546
|
+
const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
|
|
2547
|
+
React__namespace.useEffect(() => {
|
|
2548
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2549
|
+
if (p.isOpen) {
|
|
2550
|
+
p.onClose();
|
|
2551
|
+
}
|
|
2552
|
+
});
|
|
2553
|
+
return escapeRemover;
|
|
2554
|
+
}, [p.isOpen]);
|
|
2555
|
+
useIgnoreMount(() => {
|
|
2556
|
+
if (!p.__asDateInputCalendar) {
|
|
2557
|
+
if (p.isOpen) {
|
|
2558
|
+
const content = document.getElementById(p.focusContentId);
|
|
2559
|
+
if (content) {
|
|
2560
|
+
content.focus();
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
else {
|
|
2564
|
+
const parent = document.getElementById(p.focusParentId);
|
|
2565
|
+
if (parent) {
|
|
2566
|
+
parent.focus();
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
}, [p.isOpen]);
|
|
2571
|
+
return (React__namespace.createElement(reactTinyPopover.Popover, { containerClassName: getPopoverContainerClass(theme), reposition: resposition, isOpen: p.isOpen, positions: getPopoverPositions(p), onClickOutside: p.onClose, content: ({ position, childRect, popoverRect }) => (React__namespace.createElement(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: getPopoverArrowColor(theme, p), arrowSize: popoverArrowSize },
|
|
2572
|
+
React__namespace.createElement(TabLocker, null,
|
|
2573
|
+
React__namespace.createElement("div", { onKeyDown: e => {
|
|
2574
|
+
if (e.code === 'Escape') {
|
|
2575
|
+
e.stopPropagation();
|
|
2576
|
+
e.preventDefault();
|
|
2577
|
+
p.onClose();
|
|
2578
|
+
}
|
|
2579
|
+
}, role: 'dialog', "aria-modal": true, "aria-label": p.ariaLabel, className: getPopoverContentWrapperClass(theme, p) }, p.content)))) },
|
|
2580
|
+
React__namespace.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
|
|
2581
|
+
};
|
|
2582
|
+
|
|
2510
2583
|
const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
|
|
2511
2584
|
const datePattern = dateRegex.source;
|
|
2512
2585
|
const invalidDateMessage = 'Invalid date.';
|
|
@@ -2636,9 +2709,16 @@ const DateInput = React__namespace.forwardRef((props, ref) => {
|
|
|
2636
2709
|
}
|
|
2637
2710
|
(_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
|
|
2638
2711
|
} })));
|
|
2639
|
-
return (React__namespace.createElement(
|
|
2712
|
+
return (React__namespace.createElement(DialogPopover, { ariaLabel: 'Calendar',
|
|
2713
|
+
// Focus is handled here so we're opting out of the popover behavior in the most hackish way.
|
|
2714
|
+
// When there's time, remove the logic from here that now exists in the DialogPopover.
|
|
2715
|
+
focusContentId: '', focusParentId: '', __asDateInputCalendar: true, onClose: () => {
|
|
2640
2716
|
toggleCalendar(false);
|
|
2641
|
-
},
|
|
2717
|
+
},
|
|
2718
|
+
// above two lines are required due to ARIA changes.
|
|
2719
|
+
// we don't need to re-do this component since it already manages it's own focus in a very
|
|
2720
|
+
// complicated way
|
|
2721
|
+
reposition: reposition, isOpen: showCalendar, parent: input, content: (React__namespace.createElement("div", { ref: popover, className: css.css({
|
|
2642
2722
|
paddingLeft: '1rem',
|
|
2643
2723
|
paddingRight: '1rem',
|
|
2644
2724
|
paddingBottom: '1rem'
|
|
@@ -2917,7 +2997,7 @@ const Nav = (props) => {
|
|
|
2917
2997
|
nav.current.classList.add(classNavShowing);
|
|
2918
2998
|
setTimeout(() => {
|
|
2919
2999
|
var _a;
|
|
2920
|
-
(_a = document.
|
|
3000
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2921
3001
|
}, slideMs + 1);
|
|
2922
3002
|
}
|
|
2923
3003
|
}
|
|
@@ -4526,12 +4606,68 @@ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
|
|
|
4526
4606
|
React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4527
4607
|
});
|
|
4528
4608
|
|
|
4609
|
+
let clearTimerId = undefined;
|
|
4610
|
+
/** Allows for status notificaiton methods for screen readers.
|
|
4611
|
+
* This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
|
|
4612
|
+
function useAriaLiveRegion() {
|
|
4613
|
+
const id = 'MknAriaLiveRegion';
|
|
4614
|
+
if (!document.getElementById(id)) {
|
|
4615
|
+
const div = document.createElement('div');
|
|
4616
|
+
div.id = id;
|
|
4617
|
+
// different sources cannot decide if this is needed.
|
|
4618
|
+
// "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
|
|
4619
|
+
div.role = 'status';
|
|
4620
|
+
div.ariaLive = 'polite';
|
|
4621
|
+
div.ariaAtomic = 'true';
|
|
4622
|
+
div.style.position = 'absolute';
|
|
4623
|
+
div.style.width = '1px';
|
|
4624
|
+
div.style.height = '1px';
|
|
4625
|
+
div.style.padding = '0px';
|
|
4626
|
+
div.style.margin = '-1px';
|
|
4627
|
+
div.style.overflow = 'hidden';
|
|
4628
|
+
div.style.whiteSpace = 'nowrap';
|
|
4629
|
+
document.body.prepend(div);
|
|
4630
|
+
}
|
|
4631
|
+
const clearNotification = () => {
|
|
4632
|
+
if (clearTimerId) {
|
|
4633
|
+
clearTimeout(clearTimerId);
|
|
4634
|
+
}
|
|
4635
|
+
const element = document.getElementById(id);
|
|
4636
|
+
if (!element) {
|
|
4637
|
+
return;
|
|
4638
|
+
}
|
|
4639
|
+
element.textContent = '';
|
|
4640
|
+
};
|
|
4641
|
+
return {
|
|
4642
|
+
/**
|
|
4643
|
+
* @param message - The text to be read by the screen reader.
|
|
4644
|
+
* @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
|
|
4645
|
+
*/
|
|
4646
|
+
notify: (message, clearTimoutMs) => {
|
|
4647
|
+
if (clearTimerId) {
|
|
4648
|
+
clearTimeout(clearTimerId);
|
|
4649
|
+
}
|
|
4650
|
+
const element = document.getElementById(id);
|
|
4651
|
+
if (!element) {
|
|
4652
|
+
return;
|
|
4653
|
+
}
|
|
4654
|
+
element.textContent = message;
|
|
4655
|
+
clearTimerId = setTimeout(() => {
|
|
4656
|
+
// this is considered a good practice. if you leave text here, some screen readers will read it out randomly as you navigate around the page.
|
|
4657
|
+
clearNotification();
|
|
4658
|
+
}, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
|
|
4659
|
+
},
|
|
4660
|
+
clearNotification
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4529
4664
|
const WaitingIndicator = (p) => {
|
|
4530
4665
|
var _a, _b, _c;
|
|
4531
4666
|
const [show, setShow] = React.useState(p.show);
|
|
4532
4667
|
const hideTimer = React.useRef(0);
|
|
4533
4668
|
const lastShowStatus = React.useRef(false);
|
|
4534
4669
|
const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
4670
|
+
const { notify, clearNotification } = useAriaLiveRegion();
|
|
4535
4671
|
if (p.__debug) {
|
|
4536
4672
|
React.useEffect(() => {
|
|
4537
4673
|
log('mounted');
|
|
@@ -4578,9 +4714,16 @@ const WaitingIndicator = (p) => {
|
|
|
4578
4714
|
log('ignoring show change due to hideTimer ticking');
|
|
4579
4715
|
}
|
|
4580
4716
|
}
|
|
4717
|
+
if (p.show) {
|
|
4718
|
+
// set to a very long time so the hiding of the waiting indicator clears it.
|
|
4719
|
+
notify('Loading content.', 60000);
|
|
4720
|
+
}
|
|
4721
|
+
else {
|
|
4722
|
+
clearNotification();
|
|
4723
|
+
}
|
|
4581
4724
|
}, [p.show]);
|
|
4582
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4583
|
-
return (React.createElement(Modal, { id: id, __debug: p.__debug,
|
|
4725
|
+
const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
|
|
4726
|
+
return (React.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
|
|
4584
4727
|
/* noop */
|
|
4585
4728
|
}, className: "waitingIndicator", show: show },
|
|
4586
4729
|
React.createElement("div", { className: css.css({
|
|
@@ -5180,6 +5323,7 @@ exports.Checkbox = Checkbox;
|
|
|
5180
5323
|
exports.ConfirmModal = ConfirmModal;
|
|
5181
5324
|
exports.CopyButton = CopyButton;
|
|
5182
5325
|
exports.DateInput = DateInput;
|
|
5326
|
+
exports.DialogPopover = DialogPopover;
|
|
5183
5327
|
exports.Divider = Divider;
|
|
5184
5328
|
exports.ErrorModal = ErrorModal;
|
|
5185
5329
|
exports.FileUploader = FileUploader;
|
|
@@ -5208,7 +5352,6 @@ exports.OmniLink = OmniLink;
|
|
|
5208
5352
|
exports.PagedResult = PagedResult;
|
|
5209
5353
|
exports.Pager = Pager;
|
|
5210
5354
|
exports.Picker = Picker;
|
|
5211
|
-
exports.Popover = Popover;
|
|
5212
5355
|
exports.ProgressBar = ProgressBar;
|
|
5213
5356
|
exports.SearchBox = SearchBox;
|
|
5214
5357
|
exports.Slider = Slider;
|
|
@@ -5229,6 +5372,7 @@ exports.ThemeRenderer = ThemeRenderer;
|
|
|
5229
5372
|
exports.ToggleButton = ToggleButton;
|
|
5230
5373
|
exports.ToggleButtonGroup = ToggleButtonGroup;
|
|
5231
5374
|
exports.TogglePasswordInput = TogglePasswordInput;
|
|
5375
|
+
exports.TooltipPopover = TooltipPopover;
|
|
5232
5376
|
exports.Tr = Tr;
|
|
5233
5377
|
exports.WaitingIndicator = WaitingIndicator;
|
|
5234
5378
|
exports.calcDynamicThemeProps = calcDynamicThemeProps;
|
|
@@ -5238,6 +5382,7 @@ exports.getCurrencyDisplay = getCurrencyDisplay;
|
|
|
5238
5382
|
exports.getFileSizeDisplay = getFileSizeDisplay;
|
|
5239
5383
|
exports.modalScrollFixClassName = modalScrollFixClassName;
|
|
5240
5384
|
exports.useAccordianState = useAccordianState;
|
|
5385
|
+
exports.useAriaLiveRegion = useAriaLiveRegion;
|
|
5241
5386
|
exports.useBooleanChanged = useBooleanChanged;
|
|
5242
5387
|
exports.useIgnoreMount = useIgnoreMount;
|
|
5243
5388
|
exports.useMediaQuery = useMediaQuery;
|