@mackin.com/styleguide 11.0.2 → 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 +68 -22
- package/index.esm.js +254 -79
- package/index.js +255 -78
- 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. */
|
|
@@ -886,8 +915,12 @@ interface TabHeaderTabProps {
|
|
|
886
915
|
title?: string;
|
|
887
916
|
}
|
|
888
917
|
interface TabHeaderProps {
|
|
918
|
+
/** Required for generating element IDs for ARIA. */
|
|
919
|
+
id: string;
|
|
889
920
|
tabs: TabHeaderTabProps[];
|
|
890
|
-
|
|
921
|
+
ariaLabel: string;
|
|
922
|
+
/** The ID of the content panel with `role=tabpanel` this header is associated with. */
|
|
923
|
+
ariaControlsId: string;
|
|
891
924
|
/** Defaults to 10rem. */
|
|
892
925
|
maxTabWidth?: string;
|
|
893
926
|
/** Defaults to 'tab'. */
|
|
@@ -1110,13 +1143,15 @@ interface ThemeRendererProps extends MackinTheme {
|
|
|
1110
1143
|
declare const ThemeRenderer: (p: ThemeRendererProps) => React.JSX.Element;
|
|
1111
1144
|
|
|
1112
1145
|
interface TabContainerProps {
|
|
1146
|
+
/** Required for generating element IDs for ARIA. */
|
|
1147
|
+
id: string;
|
|
1148
|
+
ariaLabel: string;
|
|
1113
1149
|
tabs: {
|
|
1114
1150
|
name: string | JSX.Element;
|
|
1115
1151
|
/** The HTML title of the tab button. Defaults to 'name' prop. */
|
|
1116
1152
|
title?: string;
|
|
1117
1153
|
getContent: () => JSX.Element;
|
|
1118
1154
|
}[];
|
|
1119
|
-
id?: string;
|
|
1120
1155
|
/** Defaults to 10rem. */
|
|
1121
1156
|
maxTabWidth?: string;
|
|
1122
1157
|
/** Defaults to 'tab'. */
|
|
@@ -1189,4 +1224,15 @@ declare const LocalizationProvider: (p: {
|
|
|
1189
1224
|
__debug?: boolean;
|
|
1190
1225
|
}) => React__default.JSX.Element;
|
|
1191
1226
|
|
|
1192
|
-
|
|
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
|
|
|
@@ -1580,7 +1580,7 @@ const Checkbox = (props) => {
|
|
|
1580
1580
|
`}
|
|
1581
1581
|
`;
|
|
1582
1582
|
const iconStyles = css `
|
|
1583
|
-
${!!label && `
|
|
1583
|
+
${!!label && !hideLabel && `
|
|
1584
1584
|
margin-right: 0.5rem;
|
|
1585
1585
|
`}
|
|
1586
1586
|
${props.disabled && `
|
|
@@ -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'
|
|
@@ -2883,7 +2961,6 @@ const Nav = (props) => {
|
|
|
2883
2961
|
padding-top:0;
|
|
2884
2962
|
`;
|
|
2885
2963
|
React.useEffect(() => {
|
|
2886
|
-
console.log('useEffect');
|
|
2887
2964
|
if (!backdrop.showing) {
|
|
2888
2965
|
props.toggle(false);
|
|
2889
2966
|
}
|
|
@@ -2894,15 +2971,13 @@ const Nav = (props) => {
|
|
|
2894
2971
|
backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
|
|
2895
2972
|
}, props.show);
|
|
2896
2973
|
React.useLayoutEffect(() => {
|
|
2897
|
-
console.log('useLayoutEffect');
|
|
2898
2974
|
if (nav && nav.current) {
|
|
2899
2975
|
if (props.show) {
|
|
2900
2976
|
if (!nav.current.classList.contains(classNavShowing)) {
|
|
2901
2977
|
nav.current.classList.add(classNavShowing);
|
|
2902
2978
|
setTimeout(() => {
|
|
2903
2979
|
var _a;
|
|
2904
|
-
(_a = document.
|
|
2905
|
-
console.log(props.focusSelector, document.querySelector(props.focusSelector), 'focused');
|
|
2980
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2906
2981
|
}, slideMs + 1);
|
|
2907
2982
|
}
|
|
2908
2983
|
}
|
|
@@ -4095,8 +4170,37 @@ const TabHeader = (p) => {
|
|
|
4095
4170
|
borderBottom: theme.controls.border,
|
|
4096
4171
|
paddingBottom: '1rem'
|
|
4097
4172
|
});
|
|
4173
|
+
function onTabSelect(index, tabId, focusAfter) {
|
|
4174
|
+
const onChange = () => {
|
|
4175
|
+
var _a;
|
|
4176
|
+
setTabIndex(index);
|
|
4177
|
+
(_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
|
|
4178
|
+
if (focusAfter) {
|
|
4179
|
+
setTimeout(() => {
|
|
4180
|
+
var _a;
|
|
4181
|
+
(_a = document.getElementById(tabId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4182
|
+
}, 0);
|
|
4183
|
+
}
|
|
4184
|
+
};
|
|
4185
|
+
if (p.onBeforeTabChanged) {
|
|
4186
|
+
setTabsChanging(true);
|
|
4187
|
+
p.onBeforeTabChanged(index)
|
|
4188
|
+
.then(() => {
|
|
4189
|
+
onChange();
|
|
4190
|
+
})
|
|
4191
|
+
.catch(() => {
|
|
4192
|
+
/* do nothing */
|
|
4193
|
+
})
|
|
4194
|
+
.finally(() => {
|
|
4195
|
+
setTabsChanging(false);
|
|
4196
|
+
});
|
|
4197
|
+
}
|
|
4198
|
+
else {
|
|
4199
|
+
onChange();
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4098
4202
|
return (React.createElement("div", { className: "tabHeader" },
|
|
4099
|
-
React.createElement("ul", { className: cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
|
|
4203
|
+
React.createElement("ul", { role: 'tablist', "aria-label": p.ariaLabel, className: cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
|
|
4100
4204
|
var _a, _b;
|
|
4101
4205
|
const active = index === tabIndex;
|
|
4102
4206
|
let tabStyles;
|
|
@@ -4140,28 +4244,31 @@ const TabHeader = (p) => {
|
|
|
4140
4244
|
else {
|
|
4141
4245
|
buttonContent = tab.name;
|
|
4142
4246
|
}
|
|
4247
|
+
const tabId = getTabHeaderTabId(p.id, index);
|
|
4143
4248
|
return (React.createElement("li", { key: index, className: cx(tabStyles, p.tabClassName) },
|
|
4144
|
-
React.createElement(Button, {
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
}
|
|
4156
|
-
.catch(() => {
|
|
4157
|
-
/* do nothing */
|
|
4158
|
-
})
|
|
4159
|
-
.finally(() => {
|
|
4160
|
-
setTabsChanging(false);
|
|
4161
|
-
});
|
|
4249
|
+
React.createElement(Button, { id: tabId, tabIndex: active ? 0 : -1, role: "tab", "aria-controls": p.ariaControlsId, "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
|
|
4250
|
+
onTabSelect(index, tabId, false);
|
|
4251
|
+
}, onKeyDown: e => {
|
|
4252
|
+
e.stopPropagation();
|
|
4253
|
+
let newIndex = index;
|
|
4254
|
+
if (e.code === 'ArrowLeft') {
|
|
4255
|
+
if (index === 0) {
|
|
4256
|
+
newIndex = p.tabs.length - 1;
|
|
4257
|
+
}
|
|
4258
|
+
else {
|
|
4259
|
+
newIndex = index - 1;
|
|
4260
|
+
}
|
|
4162
4261
|
}
|
|
4163
|
-
else {
|
|
4164
|
-
|
|
4262
|
+
else if (e.code === 'ArrowRight') {
|
|
4263
|
+
if (index === p.tabs.length - 1) {
|
|
4264
|
+
newIndex = 0;
|
|
4265
|
+
}
|
|
4266
|
+
else {
|
|
4267
|
+
newIndex = index + 1;
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
if (newIndex !== index) {
|
|
4271
|
+
onTabSelect(newIndex, getTabHeaderTabId(p.id, newIndex), true);
|
|
4165
4272
|
}
|
|
4166
4273
|
} }, buttonContent)));
|
|
4167
4274
|
})),
|
|
@@ -4173,6 +4280,9 @@ const TabHeader = (p) => {
|
|
|
4173
4280
|
position: 'relative'
|
|
4174
4281
|
}), p.tabHeaderDividerClassName) }))));
|
|
4175
4282
|
};
|
|
4283
|
+
function getTabHeaderTabId(tabHeaderId, tabIndex) {
|
|
4284
|
+
return `${tabHeaderId}_tab_${tabIndex}`;
|
|
4285
|
+
}
|
|
4176
4286
|
|
|
4177
4287
|
const Table = (props) => {
|
|
4178
4288
|
const theme = useThemeSafely();
|
|
@@ -4476,12 +4586,68 @@ const TogglePasswordInput = React.forwardRef((props, ref) => {
|
|
|
4476
4586
|
React.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4477
4587
|
});
|
|
4478
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
|
+
|
|
4479
4644
|
const WaitingIndicator = (p) => {
|
|
4480
4645
|
var _a, _b, _c;
|
|
4481
4646
|
const [show, setShow] = useState(p.show);
|
|
4482
4647
|
const hideTimer = useRef(0);
|
|
4483
4648
|
const lastShowStatus = useRef(false);
|
|
4484
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();
|
|
4485
4651
|
if (p.__debug) {
|
|
4486
4652
|
useEffect(() => {
|
|
4487
4653
|
log('mounted');
|
|
@@ -4528,9 +4694,16 @@ const WaitingIndicator = (p) => {
|
|
|
4528
4694
|
log('ignoring show change due to hideTimer ticking');
|
|
4529
4695
|
}
|
|
4530
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
|
+
}
|
|
4531
4704
|
}, [p.show]);
|
|
4532
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4533
|
-
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: () => {
|
|
4534
4707
|
/* noop */
|
|
4535
4708
|
}, className: "waitingIndicator", show: show },
|
|
4536
4709
|
React__default.createElement("div", { className: css({
|
|
@@ -4942,15 +5115,17 @@ const TabContainer = (p) => {
|
|
|
4942
5115
|
var _a;
|
|
4943
5116
|
const [tabIndex, setTabIndex] = React.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
|
|
4944
5117
|
const theme = useThemeSafely();
|
|
5118
|
+
const tabPanelId = `${p.id}_tabpanel`;
|
|
5119
|
+
const tabHeaderId = `${p.id}_TabHeader`;
|
|
4945
5120
|
return (React.createElement("div", { className: css({
|
|
4946
5121
|
label: 'TabContainer'
|
|
4947
5122
|
}) },
|
|
4948
|
-
React.createElement(TabHeader, { tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: newIndex => {
|
|
5123
|
+
React.createElement(TabHeader, { id: tabHeaderId, ariaControlsId: tabPanelId, ariaLabel: p.ariaLabel, tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: (newIndex) => {
|
|
4949
5124
|
var _a;
|
|
4950
5125
|
setTabIndex(newIndex);
|
|
4951
5126
|
(_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, newIndex);
|
|
4952
5127
|
} }),
|
|
4953
|
-
React.createElement("div", { className: cx(css({
|
|
5128
|
+
React.createElement("div", { role: 'tabpanel', id: tabPanelId, "aria-labelledby": getTabHeaderTabId(tabHeaderId, tabIndex), className: cx(css({
|
|
4954
5129
|
label: 'TabContainerContent',
|
|
4955
5130
|
padding: '1rem',
|
|
4956
5131
|
borderLeft: theme.controls.border,
|
|
@@ -5114,5 +5289,5 @@ const LocalizationProvider = (p) => {
|
|
|
5114
5289
|
} }, p.children));
|
|
5115
5290
|
};
|
|
5116
5291
|
|
|
5117
|
-
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 };
|
|
5118
5293
|
//# sourceMappingURL=index.esm.js.map
|
package/index.js
CHANGED
|
@@ -1598,7 +1598,7 @@ const Checkbox = (props) => {
|
|
|
1598
1598
|
`}
|
|
1599
1599
|
`;
|
|
1600
1600
|
const iconStyles = css.css `
|
|
1601
|
-
${!!label && `
|
|
1601
|
+
${!!label && !hideLabel && `
|
|
1602
1602
|
margin-right: 0.5rem;
|
|
1603
1603
|
`}
|
|
1604
1604
|
${props.disabled && `
|
|
@@ -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'
|
|
@@ -2901,7 +2979,6 @@ const Nav = (props) => {
|
|
|
2901
2979
|
padding-top:0;
|
|
2902
2980
|
`;
|
|
2903
2981
|
React__namespace.useEffect(() => {
|
|
2904
|
-
console.log('useEffect');
|
|
2905
2982
|
if (!backdrop.showing) {
|
|
2906
2983
|
props.toggle(false);
|
|
2907
2984
|
}
|
|
@@ -2912,15 +2989,13 @@ const Nav = (props) => {
|
|
|
2912
2989
|
backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
|
|
2913
2990
|
}, props.show);
|
|
2914
2991
|
React__namespace.useLayoutEffect(() => {
|
|
2915
|
-
console.log('useLayoutEffect');
|
|
2916
2992
|
if (nav && nav.current) {
|
|
2917
2993
|
if (props.show) {
|
|
2918
2994
|
if (!nav.current.classList.contains(classNavShowing)) {
|
|
2919
2995
|
nav.current.classList.add(classNavShowing);
|
|
2920
2996
|
setTimeout(() => {
|
|
2921
2997
|
var _a;
|
|
2922
|
-
(_a = document.
|
|
2923
|
-
console.log(props.focusSelector, document.querySelector(props.focusSelector), 'focused');
|
|
2998
|
+
(_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
2924
2999
|
}, slideMs + 1);
|
|
2925
3000
|
}
|
|
2926
3001
|
}
|
|
@@ -4113,8 +4188,37 @@ const TabHeader = (p) => {
|
|
|
4113
4188
|
borderBottom: theme.controls.border,
|
|
4114
4189
|
paddingBottom: '1rem'
|
|
4115
4190
|
});
|
|
4191
|
+
function onTabSelect(index, tabId, focusAfter) {
|
|
4192
|
+
const onChange = () => {
|
|
4193
|
+
var _a;
|
|
4194
|
+
setTabIndex(index);
|
|
4195
|
+
(_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
|
|
4196
|
+
if (focusAfter) {
|
|
4197
|
+
setTimeout(() => {
|
|
4198
|
+
var _a;
|
|
4199
|
+
(_a = document.getElementById(tabId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4200
|
+
}, 0);
|
|
4201
|
+
}
|
|
4202
|
+
};
|
|
4203
|
+
if (p.onBeforeTabChanged) {
|
|
4204
|
+
setTabsChanging(true);
|
|
4205
|
+
p.onBeforeTabChanged(index)
|
|
4206
|
+
.then(() => {
|
|
4207
|
+
onChange();
|
|
4208
|
+
})
|
|
4209
|
+
.catch(() => {
|
|
4210
|
+
/* do nothing */
|
|
4211
|
+
})
|
|
4212
|
+
.finally(() => {
|
|
4213
|
+
setTabsChanging(false);
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
else {
|
|
4217
|
+
onChange();
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4116
4220
|
return (React__namespace.createElement("div", { className: "tabHeader" },
|
|
4117
|
-
React__namespace.createElement("ul", { className: css.cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
|
|
4221
|
+
React__namespace.createElement("ul", { role: 'tablist', "aria-label": p.ariaLabel, className: css.cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
|
|
4118
4222
|
var _a, _b;
|
|
4119
4223
|
const active = index === tabIndex;
|
|
4120
4224
|
let tabStyles;
|
|
@@ -4158,28 +4262,31 @@ const TabHeader = (p) => {
|
|
|
4158
4262
|
else {
|
|
4159
4263
|
buttonContent = tab.name;
|
|
4160
4264
|
}
|
|
4265
|
+
const tabId = getTabHeaderTabId(p.id, index);
|
|
4161
4266
|
return (React__namespace.createElement("li", { key: index, className: css.cx(tabStyles, p.tabClassName) },
|
|
4162
|
-
React__namespace.createElement(Button, {
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
}
|
|
4174
|
-
.catch(() => {
|
|
4175
|
-
/* do nothing */
|
|
4176
|
-
})
|
|
4177
|
-
.finally(() => {
|
|
4178
|
-
setTabsChanging(false);
|
|
4179
|
-
});
|
|
4267
|
+
React__namespace.createElement(Button, { id: tabId, tabIndex: active ? 0 : -1, role: "tab", "aria-controls": p.ariaControlsId, "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
|
|
4268
|
+
onTabSelect(index, tabId, false);
|
|
4269
|
+
}, onKeyDown: e => {
|
|
4270
|
+
e.stopPropagation();
|
|
4271
|
+
let newIndex = index;
|
|
4272
|
+
if (e.code === 'ArrowLeft') {
|
|
4273
|
+
if (index === 0) {
|
|
4274
|
+
newIndex = p.tabs.length - 1;
|
|
4275
|
+
}
|
|
4276
|
+
else {
|
|
4277
|
+
newIndex = index - 1;
|
|
4278
|
+
}
|
|
4180
4279
|
}
|
|
4181
|
-
else {
|
|
4182
|
-
|
|
4280
|
+
else if (e.code === 'ArrowRight') {
|
|
4281
|
+
if (index === p.tabs.length - 1) {
|
|
4282
|
+
newIndex = 0;
|
|
4283
|
+
}
|
|
4284
|
+
else {
|
|
4285
|
+
newIndex = index + 1;
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
if (newIndex !== index) {
|
|
4289
|
+
onTabSelect(newIndex, getTabHeaderTabId(p.id, newIndex), true);
|
|
4183
4290
|
}
|
|
4184
4291
|
} }, buttonContent)));
|
|
4185
4292
|
})),
|
|
@@ -4191,6 +4298,9 @@ const TabHeader = (p) => {
|
|
|
4191
4298
|
position: 'relative'
|
|
4192
4299
|
}), p.tabHeaderDividerClassName) }))));
|
|
4193
4300
|
};
|
|
4301
|
+
function getTabHeaderTabId(tabHeaderId, tabIndex) {
|
|
4302
|
+
return `${tabHeaderId}_tab_${tabIndex}`;
|
|
4303
|
+
}
|
|
4194
4304
|
|
|
4195
4305
|
const Table = (props) => {
|
|
4196
4306
|
const theme = useThemeSafely();
|
|
@@ -4494,12 +4604,68 @@ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
|
|
|
4494
4604
|
React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
|
|
4495
4605
|
});
|
|
4496
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
|
+
|
|
4497
4662
|
const WaitingIndicator = (p) => {
|
|
4498
4663
|
var _a, _b, _c;
|
|
4499
4664
|
const [show, setShow] = React.useState(p.show);
|
|
4500
4665
|
const hideTimer = React.useRef(0);
|
|
4501
4666
|
const lastShowStatus = React.useRef(false);
|
|
4502
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();
|
|
4503
4669
|
if (p.__debug) {
|
|
4504
4670
|
React.useEffect(() => {
|
|
4505
4671
|
log('mounted');
|
|
@@ -4546,9 +4712,16 @@ const WaitingIndicator = (p) => {
|
|
|
4546
4712
|
log('ignoring show change due to hideTimer ticking');
|
|
4547
4713
|
}
|
|
4548
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
|
+
}
|
|
4549
4722
|
}, [p.show]);
|
|
4550
|
-
const id = (_c = p.id) !== null && _c !== void 0 ? _c : '
|
|
4551
|
-
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: () => {
|
|
4552
4725
|
/* noop */
|
|
4553
4726
|
}, className: "waitingIndicator", show: show },
|
|
4554
4727
|
React.createElement("div", { className: css.css({
|
|
@@ -4960,15 +5133,17 @@ const TabContainer = (p) => {
|
|
|
4960
5133
|
var _a;
|
|
4961
5134
|
const [tabIndex, setTabIndex] = React__namespace.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
|
|
4962
5135
|
const theme = useThemeSafely();
|
|
5136
|
+
const tabPanelId = `${p.id}_tabpanel`;
|
|
5137
|
+
const tabHeaderId = `${p.id}_TabHeader`;
|
|
4963
5138
|
return (React__namespace.createElement("div", { className: css.css({
|
|
4964
5139
|
label: 'TabContainer'
|
|
4965
5140
|
}) },
|
|
4966
|
-
React__namespace.createElement(TabHeader, { tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: newIndex => {
|
|
5141
|
+
React__namespace.createElement(TabHeader, { id: tabHeaderId, ariaControlsId: tabPanelId, ariaLabel: p.ariaLabel, tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: (newIndex) => {
|
|
4967
5142
|
var _a;
|
|
4968
5143
|
setTabIndex(newIndex);
|
|
4969
5144
|
(_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, newIndex);
|
|
4970
5145
|
} }),
|
|
4971
|
-
React__namespace.createElement("div", { className: css.cx(css.css({
|
|
5146
|
+
React__namespace.createElement("div", { role: 'tabpanel', id: tabPanelId, "aria-labelledby": getTabHeaderTabId(tabHeaderId, tabIndex), className: css.cx(css.css({
|
|
4972
5147
|
label: 'TabContainerContent',
|
|
4973
5148
|
padding: '1rem',
|
|
4974
5149
|
borderLeft: theme.controls.border,
|
|
@@ -5146,6 +5321,7 @@ exports.Checkbox = Checkbox;
|
|
|
5146
5321
|
exports.ConfirmModal = ConfirmModal;
|
|
5147
5322
|
exports.CopyButton = CopyButton;
|
|
5148
5323
|
exports.DateInput = DateInput;
|
|
5324
|
+
exports.DialogPopover = DialogPopover;
|
|
5149
5325
|
exports.Divider = Divider;
|
|
5150
5326
|
exports.ErrorModal = ErrorModal;
|
|
5151
5327
|
exports.FileUploader = FileUploader;
|
|
@@ -5174,7 +5350,6 @@ exports.OmniLink = OmniLink;
|
|
|
5174
5350
|
exports.PagedResult = PagedResult;
|
|
5175
5351
|
exports.Pager = Pager;
|
|
5176
5352
|
exports.Picker = Picker;
|
|
5177
|
-
exports.Popover = Popover;
|
|
5178
5353
|
exports.ProgressBar = ProgressBar;
|
|
5179
5354
|
exports.SearchBox = SearchBox;
|
|
5180
5355
|
exports.Slider = Slider;
|
|
@@ -5195,6 +5370,7 @@ exports.ThemeRenderer = ThemeRenderer;
|
|
|
5195
5370
|
exports.ToggleButton = ToggleButton;
|
|
5196
5371
|
exports.ToggleButtonGroup = ToggleButtonGroup;
|
|
5197
5372
|
exports.TogglePasswordInput = TogglePasswordInput;
|
|
5373
|
+
exports.TooltipPopover = TooltipPopover;
|
|
5198
5374
|
exports.Tr = Tr;
|
|
5199
5375
|
exports.WaitingIndicator = WaitingIndicator;
|
|
5200
5376
|
exports.calcDynamicThemeProps = calcDynamicThemeProps;
|
|
@@ -5204,6 +5380,7 @@ exports.getCurrencyDisplay = getCurrencyDisplay;
|
|
|
5204
5380
|
exports.getFileSizeDisplay = getFileSizeDisplay;
|
|
5205
5381
|
exports.modalScrollFixClassName = modalScrollFixClassName;
|
|
5206
5382
|
exports.useAccordianState = useAccordianState;
|
|
5383
|
+
exports.useAriaLiveRegion = useAriaLiveRegion;
|
|
5207
5384
|
exports.useBooleanChanged = useBooleanChanged;
|
|
5208
5385
|
exports.useIgnoreMount = useIgnoreMount;
|
|
5209
5386
|
exports.useMediaQuery = useMediaQuery;
|