@mackin.com/styleguide 11.0.3 → 11.0.4
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 +193 -52
- package/index.js +194 -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,45 @@ 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
|
+
if (!p.__asDateInputCalendar) {
|
|
2531
|
+
if (p.isOpen) {
|
|
2532
|
+
const content = document.getElementById(p.focusContentId);
|
|
2533
|
+
if (content) {
|
|
2534
|
+
content.focus();
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
else {
|
|
2538
|
+
const parent = document.getElementById(p.focusParentId);
|
|
2539
|
+
if (parent) {
|
|
2540
|
+
parent.focus();
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2545
|
+
if (p.isOpen) {
|
|
2546
|
+
p.onClose();
|
|
2547
|
+
}
|
|
2548
|
+
});
|
|
2549
|
+
return escapeRemover;
|
|
2550
|
+
}, [p.isOpen]);
|
|
2551
|
+
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 },
|
|
2552
|
+
React.createElement(TabLocker, null,
|
|
2553
|
+
React.createElement("div", { onKeyDown: e => {
|
|
2554
|
+
if (e.code === 'Escape') {
|
|
2555
|
+
e.stopPropagation();
|
|
2556
|
+
e.preventDefault();
|
|
2557
|
+
p.onClose();
|
|
2558
|
+
}
|
|
2559
|
+
}, role: 'dialog', "aria-modal": true, "aria-label": p.ariaLabel, className: getPopoverContentWrapperClass(theme, p) }, p.content)))) },
|
|
2560
|
+
React.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
|
|
2561
|
+
};
|
|
2562
|
+
|
|
2492
2563
|
const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
|
|
2493
2564
|
const datePattern = dateRegex.source;
|
|
2494
2565
|
const invalidDateMessage = 'Invalid date.';
|
|
@@ -2618,9 +2689,16 @@ const DateInput = React.forwardRef((props, ref) => {
|
|
|
2618
2689
|
}
|
|
2619
2690
|
(_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
|
|
2620
2691
|
} })));
|
|
2621
|
-
return (React.createElement(
|
|
2692
|
+
return (React.createElement(DialogPopover, { ariaLabel: 'Calendar',
|
|
2693
|
+
// Focus is handled here so we're opting out of the popover behavior in the most hackish way.
|
|
2694
|
+
// When there's time, remove the logic from here that now exists in the DialogPopover.
|
|
2695
|
+
focusContentId: '', focusParentId: '', __asDateInputCalendar: true, onClose: () => {
|
|
2622
2696
|
toggleCalendar(false);
|
|
2623
|
-
},
|
|
2697
|
+
},
|
|
2698
|
+
// above two lines are required due to ARIA changes.
|
|
2699
|
+
// we don't need to re-do this component since it already manages it's own focus in a very
|
|
2700
|
+
// complicated way
|
|
2701
|
+
reposition: reposition, isOpen: showCalendar, parent: input, content: (React.createElement("div", { ref: popover, className: css({
|
|
2624
2702
|
paddingLeft: '1rem',
|
|
2625
2703
|
paddingRight: '1rem',
|
|
2626
2704
|
paddingBottom: '1rem'
|
|
@@ -2899,7 +2977,7 @@ const Nav = (props) => {
|
|
|
2899
2977
|
nav.current.classList.add(classNavShowing);
|
|
2900
2978
|
setTimeout(() => {
|
|
2901
2979
|
var _a;
|
|
2902
|
-
(_a = document.
|
|
2980
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2903
2981
|
}, slideMs + 1);
|
|
2904
2982
|
}
|
|
2905
2983
|
}
|
|
@@ -4508,12 +4586,68 @@ const TogglePasswordInput = React.forwardRef((props, ref) => {
|
|
|
4508
4586
|
React.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4509
4587
|
});
|
|
4510
4588
|
|
|
4589
|
+
let clearTimerId = undefined;
|
|
4590
|
+
/** Allows for status notificaiton methods for screen readers.
|
|
4591
|
+
* This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
|
|
4592
|
+
function useAriaLiveRegion() {
|
|
4593
|
+
const id = 'MknAriaLiveRegion';
|
|
4594
|
+
if (!document.getElementById(id)) {
|
|
4595
|
+
const div = document.createElement('div');
|
|
4596
|
+
div.id = id;
|
|
4597
|
+
// different sources cannot decide if this is needed.
|
|
4598
|
+
// "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
|
|
4599
|
+
div.role = 'status';
|
|
4600
|
+
div.ariaLive = 'polite';
|
|
4601
|
+
div.ariaAtomic = 'true';
|
|
4602
|
+
div.style.position = 'absolute';
|
|
4603
|
+
div.style.width = '1px';
|
|
4604
|
+
div.style.height = '1px';
|
|
4605
|
+
div.style.padding = '0px';
|
|
4606
|
+
div.style.margin = '-1px';
|
|
4607
|
+
div.style.overflow = 'hidden';
|
|
4608
|
+
div.style.whiteSpace = 'nowrap';
|
|
4609
|
+
document.body.prepend(div);
|
|
4610
|
+
}
|
|
4611
|
+
const clearNotification = () => {
|
|
4612
|
+
if (clearTimerId) {
|
|
4613
|
+
clearTimeout(clearTimerId);
|
|
4614
|
+
}
|
|
4615
|
+
const element = document.getElementById(id);
|
|
4616
|
+
if (!element) {
|
|
4617
|
+
return;
|
|
4618
|
+
}
|
|
4619
|
+
element.textContent = '';
|
|
4620
|
+
};
|
|
4621
|
+
return {
|
|
4622
|
+
/**
|
|
4623
|
+
* @param message - The text to be read by the screen reader.
|
|
4624
|
+
* @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
|
|
4625
|
+
*/
|
|
4626
|
+
notify: (message, clearTimoutMs) => {
|
|
4627
|
+
if (clearTimerId) {
|
|
4628
|
+
clearTimeout(clearTimerId);
|
|
4629
|
+
}
|
|
4630
|
+
const element = document.getElementById(id);
|
|
4631
|
+
if (!element) {
|
|
4632
|
+
return;
|
|
4633
|
+
}
|
|
4634
|
+
element.textContent = message;
|
|
4635
|
+
clearTimerId = setTimeout(() => {
|
|
4636
|
+
// 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.
|
|
4637
|
+
clearNotification();
|
|
4638
|
+
}, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
|
|
4639
|
+
},
|
|
4640
|
+
clearNotification
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4511
4644
|
const WaitingIndicator = (p) => {
|
|
4512
4645
|
var _a, _b, _c;
|
|
4513
4646
|
const [show, setShow] = useState(p.show);
|
|
4514
4647
|
const hideTimer = useRef(0);
|
|
4515
4648
|
const lastShowStatus = useRef(false);
|
|
4516
4649
|
const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
4650
|
+
const { notify, clearNotification } = useAriaLiveRegion();
|
|
4517
4651
|
if (p.__debug) {
|
|
4518
4652
|
useEffect(() => {
|
|
4519
4653
|
log('mounted');
|
|
@@ -4560,9 +4694,16 @@ const WaitingIndicator = (p) => {
|
|
|
4560
4694
|
log('ignoring show change due to hideTimer ticking');
|
|
4561
4695
|
}
|
|
4562
4696
|
}
|
|
4697
|
+
if (p.show) {
|
|
4698
|
+
// set to a very long time so the hiding of the waiting indicator clears it.
|
|
4699
|
+
notify('Loading content.', 60000);
|
|
4700
|
+
}
|
|
4701
|
+
else {
|
|
4702
|
+
clearNotification();
|
|
4703
|
+
}
|
|
4563
4704
|
}, [p.show]);
|
|
4564
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4565
|
-
return (React__default.createElement(Modal, { id: id, __debug: p.__debug,
|
|
4705
|
+
const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
|
|
4706
|
+
return (React__default.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
|
|
4566
4707
|
/* noop */
|
|
4567
4708
|
}, className: "waitingIndicator", show: show },
|
|
4568
4709
|
React__default.createElement("div", { className: css({
|
|
@@ -5148,5 +5289,5 @@ const LocalizationProvider = (p) => {
|
|
|
5148
5289
|
} }, p.children));
|
|
5149
5290
|
};
|
|
5150
5291
|
|
|
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,
|
|
5292
|
+
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
5293
|
//# 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,45 @@ 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
|
+
if (!p.__asDateInputCalendar) {
|
|
2549
|
+
if (p.isOpen) {
|
|
2550
|
+
const content = document.getElementById(p.focusContentId);
|
|
2551
|
+
if (content) {
|
|
2552
|
+
content.focus();
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
else {
|
|
2556
|
+
const parent = document.getElementById(p.focusParentId);
|
|
2557
|
+
if (parent) {
|
|
2558
|
+
parent.focus();
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
const escapeRemover = createBodyEscapeHandler(() => {
|
|
2563
|
+
if (p.isOpen) {
|
|
2564
|
+
p.onClose();
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
return escapeRemover;
|
|
2568
|
+
}, [p.isOpen]);
|
|
2569
|
+
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 },
|
|
2570
|
+
React__namespace.createElement(TabLocker, null,
|
|
2571
|
+
React__namespace.createElement("div", { onKeyDown: e => {
|
|
2572
|
+
if (e.code === 'Escape') {
|
|
2573
|
+
e.stopPropagation();
|
|
2574
|
+
e.preventDefault();
|
|
2575
|
+
p.onClose();
|
|
2576
|
+
}
|
|
2577
|
+
}, role: 'dialog', "aria-modal": true, "aria-label": p.ariaLabel, className: getPopoverContentWrapperClass(theme, p) }, p.content)))) },
|
|
2578
|
+
React__namespace.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
|
|
2579
|
+
};
|
|
2580
|
+
|
|
2510
2581
|
const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
|
|
2511
2582
|
const datePattern = dateRegex.source;
|
|
2512
2583
|
const invalidDateMessage = 'Invalid date.';
|
|
@@ -2636,9 +2707,16 @@ const DateInput = React__namespace.forwardRef((props, ref) => {
|
|
|
2636
2707
|
}
|
|
2637
2708
|
(_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
|
|
2638
2709
|
} })));
|
|
2639
|
-
return (React__namespace.createElement(
|
|
2710
|
+
return (React__namespace.createElement(DialogPopover, { ariaLabel: 'Calendar',
|
|
2711
|
+
// Focus is handled here so we're opting out of the popover behavior in the most hackish way.
|
|
2712
|
+
// When there's time, remove the logic from here that now exists in the DialogPopover.
|
|
2713
|
+
focusContentId: '', focusParentId: '', __asDateInputCalendar: true, onClose: () => {
|
|
2640
2714
|
toggleCalendar(false);
|
|
2641
|
-
},
|
|
2715
|
+
},
|
|
2716
|
+
// above two lines are required due to ARIA changes.
|
|
2717
|
+
// we don't need to re-do this component since it already manages it's own focus in a very
|
|
2718
|
+
// complicated way
|
|
2719
|
+
reposition: reposition, isOpen: showCalendar, parent: input, content: (React__namespace.createElement("div", { ref: popover, className: css.css({
|
|
2642
2720
|
paddingLeft: '1rem',
|
|
2643
2721
|
paddingRight: '1rem',
|
|
2644
2722
|
paddingBottom: '1rem'
|
|
@@ -2917,7 +2995,7 @@ const Nav = (props) => {
|
|
|
2917
2995
|
nav.current.classList.add(classNavShowing);
|
|
2918
2996
|
setTimeout(() => {
|
|
2919
2997
|
var _a;
|
|
2920
|
-
(_a = document.
|
|
2998
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2921
2999
|
}, slideMs + 1);
|
|
2922
3000
|
}
|
|
2923
3001
|
}
|
|
@@ -4526,12 +4604,68 @@ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
|
|
|
4526
4604
|
React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4527
4605
|
});
|
|
4528
4606
|
|
|
4607
|
+
let clearTimerId = undefined;
|
|
4608
|
+
/** Allows for status notificaiton methods for screen readers.
|
|
4609
|
+
* This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
|
|
4610
|
+
function useAriaLiveRegion() {
|
|
4611
|
+
const id = 'MknAriaLiveRegion';
|
|
4612
|
+
if (!document.getElementById(id)) {
|
|
4613
|
+
const div = document.createElement('div');
|
|
4614
|
+
div.id = id;
|
|
4615
|
+
// different sources cannot decide if this is needed.
|
|
4616
|
+
// "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
|
|
4617
|
+
div.role = 'status';
|
|
4618
|
+
div.ariaLive = 'polite';
|
|
4619
|
+
div.ariaAtomic = 'true';
|
|
4620
|
+
div.style.position = 'absolute';
|
|
4621
|
+
div.style.width = '1px';
|
|
4622
|
+
div.style.height = '1px';
|
|
4623
|
+
div.style.padding = '0px';
|
|
4624
|
+
div.style.margin = '-1px';
|
|
4625
|
+
div.style.overflow = 'hidden';
|
|
4626
|
+
div.style.whiteSpace = 'nowrap';
|
|
4627
|
+
document.body.prepend(div);
|
|
4628
|
+
}
|
|
4629
|
+
const clearNotification = () => {
|
|
4630
|
+
if (clearTimerId) {
|
|
4631
|
+
clearTimeout(clearTimerId);
|
|
4632
|
+
}
|
|
4633
|
+
const element = document.getElementById(id);
|
|
4634
|
+
if (!element) {
|
|
4635
|
+
return;
|
|
4636
|
+
}
|
|
4637
|
+
element.textContent = '';
|
|
4638
|
+
};
|
|
4639
|
+
return {
|
|
4640
|
+
/**
|
|
4641
|
+
* @param message - The text to be read by the screen reader.
|
|
4642
|
+
* @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
|
|
4643
|
+
*/
|
|
4644
|
+
notify: (message, clearTimoutMs) => {
|
|
4645
|
+
if (clearTimerId) {
|
|
4646
|
+
clearTimeout(clearTimerId);
|
|
4647
|
+
}
|
|
4648
|
+
const element = document.getElementById(id);
|
|
4649
|
+
if (!element) {
|
|
4650
|
+
return;
|
|
4651
|
+
}
|
|
4652
|
+
element.textContent = message;
|
|
4653
|
+
clearTimerId = setTimeout(() => {
|
|
4654
|
+
// 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.
|
|
4655
|
+
clearNotification();
|
|
4656
|
+
}, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
|
|
4657
|
+
},
|
|
4658
|
+
clearNotification
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4529
4662
|
const WaitingIndicator = (p) => {
|
|
4530
4663
|
var _a, _b, _c;
|
|
4531
4664
|
const [show, setShow] = React.useState(p.show);
|
|
4532
4665
|
const hideTimer = React.useRef(0);
|
|
4533
4666
|
const lastShowStatus = React.useRef(false);
|
|
4534
4667
|
const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
|
|
4668
|
+
const { notify, clearNotification } = useAriaLiveRegion();
|
|
4535
4669
|
if (p.__debug) {
|
|
4536
4670
|
React.useEffect(() => {
|
|
4537
4671
|
log('mounted');
|
|
@@ -4578,9 +4712,16 @@ const WaitingIndicator = (p) => {
|
|
|
4578
4712
|
log('ignoring show change due to hideTimer ticking');
|
|
4579
4713
|
}
|
|
4580
4714
|
}
|
|
4715
|
+
if (p.show) {
|
|
4716
|
+
// set to a very long time so the hiding of the waiting indicator clears it.
|
|
4717
|
+
notify('Loading content.', 60000);
|
|
4718
|
+
}
|
|
4719
|
+
else {
|
|
4720
|
+
clearNotification();
|
|
4721
|
+
}
|
|
4581
4722
|
}, [p.show]);
|
|
4582
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4583
|
-
return (React.createElement(Modal, { id: id, __debug: p.__debug,
|
|
4723
|
+
const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
|
|
4724
|
+
return (React.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
|
|
4584
4725
|
/* noop */
|
|
4585
4726
|
}, className: "waitingIndicator", show: show },
|
|
4586
4727
|
React.createElement("div", { className: css.css({
|
|
@@ -5180,6 +5321,7 @@ exports.Checkbox = Checkbox;
|
|
|
5180
5321
|
exports.ConfirmModal = ConfirmModal;
|
|
5181
5322
|
exports.CopyButton = CopyButton;
|
|
5182
5323
|
exports.DateInput = DateInput;
|
|
5324
|
+
exports.DialogPopover = DialogPopover;
|
|
5183
5325
|
exports.Divider = Divider;
|
|
5184
5326
|
exports.ErrorModal = ErrorModal;
|
|
5185
5327
|
exports.FileUploader = FileUploader;
|
|
@@ -5208,7 +5350,6 @@ exports.OmniLink = OmniLink;
|
|
|
5208
5350
|
exports.PagedResult = PagedResult;
|
|
5209
5351
|
exports.Pager = Pager;
|
|
5210
5352
|
exports.Picker = Picker;
|
|
5211
|
-
exports.Popover = Popover;
|
|
5212
5353
|
exports.ProgressBar = ProgressBar;
|
|
5213
5354
|
exports.SearchBox = SearchBox;
|
|
5214
5355
|
exports.Slider = Slider;
|
|
@@ -5229,6 +5370,7 @@ exports.ThemeRenderer = ThemeRenderer;
|
|
|
5229
5370
|
exports.ToggleButton = ToggleButton;
|
|
5230
5371
|
exports.ToggleButtonGroup = ToggleButtonGroup;
|
|
5231
5372
|
exports.TogglePasswordInput = TogglePasswordInput;
|
|
5373
|
+
exports.TooltipPopover = TooltipPopover;
|
|
5232
5374
|
exports.Tr = Tr;
|
|
5233
5375
|
exports.WaitingIndicator = WaitingIndicator;
|
|
5234
5376
|
exports.calcDynamicThemeProps = calcDynamicThemeProps;
|
|
@@ -5238,6 +5380,7 @@ exports.getCurrencyDisplay = getCurrencyDisplay;
|
|
|
5238
5380
|
exports.getFileSizeDisplay = getFileSizeDisplay;
|
|
5239
5381
|
exports.modalScrollFixClassName = modalScrollFixClassName;
|
|
5240
5382
|
exports.useAccordianState = useAccordianState;
|
|
5383
|
+
exports.useAriaLiveRegion = useAriaLiveRegion;
|
|
5241
5384
|
exports.useBooleanChanged = useBooleanChanged;
|
|
5242
5385
|
exports.useIgnoreMount = useIgnoreMount;
|
|
5243
5386
|
exports.useMediaQuery = useMediaQuery;
|