@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.
Files changed (4) hide show
  1. package/index.d.ts +68 -22
  2. package/index.esm.js +254 -79
  3. package/index.js +255 -78
  4. 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 | null;
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
- /** Selector of the element to focus on initial show. Will default to the close button. */
417
- focusSelector?: string;
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
- __noHeader?: boolean;
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
- focusSelector: string;
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
- interface PopoverProps {
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
- id?: string;
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?: ("bottom" | "left" | "right" | "top")[] | undefined;
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
- declare const Popover: (p: PopoverProps) => React.JSX.Element;
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
- id?: string;
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
- 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, 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, Popover, 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, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
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 as Popover$1, ArrowContainer } from 'react-tiny-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.__noHeader;
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 focusSelector = (_a = p.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
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
- var _a;
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', focusSelector);
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
- const Popover = (p) => {
2392
- var _a, _b;
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
- return (React.createElement(Popover$1, { containerClassName: css({
2396
- zIndex: theme.zIndexes.tooltip
2397
- }), reposition: resposition, isOpen: p.isOpen, positions: (_b = p.positions) !== null && _b !== void 0 ? _b : ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
2398
- var _a, _b, _c, _d;
2399
- return (React.createElement(ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
2400
- React.createElement(TabLocker, null,
2401
- React.createElement("div", { className: css({
2402
- border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
2403
- borderRadius: (_c = p.border) !== null && _c !== void 0 ? _c : theme.controls.borderRadius,
2404
- boxShadow: theme.controls.boxShadow,
2405
- backgroundColor: (_d = p.backgroundColor) !== null && _d !== void 0 ? _d : theme.colors.bg,
2406
- }) }, p.content))));
2407
- } },
2408
- React.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
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 === 'modal') {
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 === 'modal') {
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
- const button = React.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
2475
- if (props.variant === 'modal' && props.modalProps) {
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.modalProps.id, __debug: props.modalProps.__debug, show: showTip, heading: props.modalProps.heading, onClose: closeTip, className: css({
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(Popover, { positions: props.positions, reposition: (_c = props.reposition) !== null && _c !== void 0 ? _c : false, isOpen: showTip, onClickOutside: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (React.createElement("div", { className: css({
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(Popover, { reposition: reposition, isOpen: showCalendar, onClickOutside: () => {
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
- }, parent: input, content: (React.createElement("div", { ref: popover, className: css({
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.querySelector(props.focusSelector)) === null || _a === void 0 ? void 0 : _a.focus();
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, { "aria-role": "tab", "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
4145
- const onChange = () => {
4146
- var _a;
4147
- setTabIndex(index);
4148
- (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
4149
- };
4150
- if (p.onBeforeTabChanged) {
4151
- setTabsChanging(true);
4152
- p.onBeforeTabChanged(index)
4153
- .then(() => {
4154
- onChange();
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
- onChange();
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 : 'WaitingIndicator';
4533
- return (React__default.createElement(Modal, { id: id, __debug: p.__debug, __noHeader: true, heading: '', onClose: () => {
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, Popover, ProgressBar, SearchBox, Slider, StyleGuideLanguage, TabContainer, TabHeader, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, TextInput, Th, ThSort, ThemeProvider, ThemeRenderer, ToggleButton, ToggleButtonGroup, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
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.__noHeader;
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 focusSelector = (_a = p.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
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
- var _a;
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', focusSelector);
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
- const Popover = (p) => {
2410
- var _a, _b;
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
- return (React__namespace.createElement(reactTinyPopover.Popover, { containerClassName: css.css({
2414
- zIndex: theme.zIndexes.tooltip
2415
- }), reposition: resposition, isOpen: p.isOpen, positions: (_b = p.positions) !== null && _b !== void 0 ? _b : ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
2416
- var _a, _b, _c, _d;
2417
- return (React__namespace.createElement(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
2418
- React__namespace.createElement(TabLocker, null,
2419
- React__namespace.createElement("div", { className: css.css({
2420
- border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
2421
- borderRadius: (_c = p.border) !== null && _c !== void 0 ? _c : theme.controls.borderRadius,
2422
- boxShadow: theme.controls.boxShadow,
2423
- backgroundColor: (_d = p.backgroundColor) !== null && _d !== void 0 ? _d : theme.colors.bg,
2424
- }) }, p.content))));
2425
- } },
2426
- React__namespace.createElement("span", { className: p.parentWrapperClassName }, p.parent)));
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 === 'modal') {
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 === 'modal') {
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
- const button = React__namespace.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
2493
- if (props.variant === 'modal' && props.modalProps) {
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.modalProps.id, __debug: props.modalProps.__debug, show: showTip, heading: props.modalProps.heading, onClose: closeTip, className: css.css({
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(Popover, { positions: props.positions, reposition: (_c = props.reposition) !== null && _c !== void 0 ? _c : false, isOpen: showTip, onClickOutside: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (React__namespace.createElement("div", { className: css.css({
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(Popover, { reposition: reposition, isOpen: showCalendar, onClickOutside: () => {
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
- }, parent: input, content: (React__namespace.createElement("div", { ref: popover, className: css.css({
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.querySelector(props.focusSelector)) === null || _a === void 0 ? void 0 : _a.focus();
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, { "aria-role": "tab", "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
4163
- const onChange = () => {
4164
- var _a;
4165
- setTabIndex(index);
4166
- (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
4167
- };
4168
- if (p.onBeforeTabChanged) {
4169
- setTabsChanging(true);
4170
- p.onBeforeTabChanged(index)
4171
- .then(() => {
4172
- onChange();
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
- onChange();
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 : 'WaitingIndicator';
4551
- return (React.createElement(Modal, { id: id, __debug: p.__debug, __noHeader: true, heading: '', onClose: () => {
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mackin.com/styleguide",
3
- "version": "11.0.2",
3
+ "version": "11.0.4",
4
4
  "description": "",
5
5
  "main": "./index.js",
6
6
  "module": "./index.esm.js",