@mackin.com/styleguide 11.0.1 → 11.0.2

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 +24 -17
  2. package/index.esm.js +76 -26
  3. package/index.js +76 -26
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -151,6 +151,7 @@ interface CheckboxProps extends Omit<React.DetailedHTMLProps<React.InputHTMLAttr
151
151
  declare const Checkbox: (props: CheckboxProps) => React.JSX.Element;
152
152
 
153
153
  interface ConfirmModalProps {
154
+ id: string;
154
155
  show: boolean;
155
156
  text: string;
156
157
  header: string;
@@ -160,7 +161,6 @@ interface ConfirmModalProps {
160
161
  cancelText?: string;
161
162
  className?: string;
162
163
  variant?: 'omg';
163
- id?: string;
164
164
  __debug?: boolean;
165
165
  }
166
166
  declare const ConfirmModal: (props: ConfirmModalProps) => React.JSX.Element;
@@ -176,9 +176,9 @@ declare const Divider: (p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHREl
176
176
  declare const ErrorModal: (props: {
177
177
  message: string;
178
178
  show: boolean;
179
- id?: string;
179
+ id: string;
180
180
  __debug?: boolean;
181
- close: () => void;
181
+ onClose: () => void;
182
182
  }) => React.JSX.Element;
183
183
 
184
184
  interface FileUploaderProps {
@@ -293,18 +293,18 @@ interface InfoTipProps {
293
293
  bgColor?: string;
294
294
  /** Defaults to nav font color. */
295
295
  fontColor?: string;
296
- /** For variant=modal only. */
297
- modalHeader?: string;
298
- /** For variant=modal only. */
299
- modalId?: string;
300
- /** For variant=modal only. */
301
- __modalDebug?: boolean;
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
302
  /** Whether to move the popover on collision with the parent's bounds. Default is false. For variant=info only. */
303
303
  reposition?: boolean;
304
304
  /** Order of positions as the Popover colides with the window edge. The default order is ['right', 'top', 'left', 'bottom']. For variant=info only. */
305
305
  positions?: ("bottom" | "left" | "right" | "top")[] | undefined;
306
306
  }
307
- declare const InfoTip: (props: InfoTipProps) => React.JSX.Element;
307
+ declare const InfoTip: (props: InfoTipProps) => React.JSX.Element | null;
308
308
 
309
309
  interface BaseInputProps extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
310
310
  rightControl?: JSX.Element;
@@ -403,30 +403,34 @@ interface ListItemProps extends React.DetailedHTMLProps<React.LiHTMLAttributes<H
403
403
  declare const ListItem: (props: ListItemProps) => React.JSX.Element;
404
404
 
405
405
  interface ModalProps {
406
+ /** Required for various ARIA support choices. */
407
+ id: string;
406
408
  show: boolean;
407
409
  children: React__default.ReactNode;
410
+ heading: string;
408
411
  /** Defaults to theme.breakpoints.tablet. */
409
412
  maxWidth?: string;
410
413
  minWidth?: string;
411
- /** Will not apply a background color to the modal body. */
412
- noBackground?: boolean;
413
- closeButton?: boolean;
414
- heading?: string;
415
414
  /** Use to override default heading styling. */
416
415
  headerClassName?: string;
417
- /** Selector of the element to focus on initial show. */
416
+ /** Selector of the element to focus on initial show. Will default to the close button. */
418
417
  focusSelector?: string;
419
418
  scrollable?: boolean;
420
- id?: string;
421
419
  /** Applied to the modal body. */
422
420
  className?: string;
423
421
  __debug?: boolean;
424
- onClick?: () => void;
422
+ /** Only used for the `WaitingIndicator`. This will break accessiblity so do not use. */
423
+ __noHeader?: boolean;
424
+ onClose: () => void;
425
425
  }
426
426
  declare const Modal: (p: ModalProps) => React__default.ReactPortal | null;
427
427
 
428
428
  declare const Nav: (props: {
429
429
  show: boolean;
430
+ /** Required for ARIA. The element to focus when first opened. */
431
+ focusSelector: string;
432
+ /** Required for ARIA. Description of the `Nav` purpose. */
433
+ ariaLabel: string;
430
434
  toggle: (show: boolean) => void;
431
435
  id?: string;
432
436
  children?: React.ReactNode;
@@ -952,6 +956,7 @@ declare const TabLocker: (props: {
952
956
  disabled?: boolean;
953
957
  children?: React.ReactNode;
954
958
  style?: React.CSSProperties;
959
+ className?: string;
955
960
  }) => React.JSX.Element;
956
961
 
957
962
  type SupportedTags = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'span' | 'div';
@@ -977,11 +982,13 @@ interface TextProps {
977
982
  /** Will remove all margin/padding from specified tag */
978
983
  noPad?: boolean;
979
984
  leftPad?: string;
985
+ id?: string;
980
986
  }
981
987
  /** Wraps common needs for displaying text. Use for all text-containing elements to save on duplicated styling. */
982
988
  declare const Text: (props: TextProps) => React.DetailedReactHTMLElement<{
983
989
  style: React.CSSProperties;
984
990
  className: string;
991
+ id: string | undefined;
985
992
  }, HTMLElement>;
986
993
 
987
994
  type BaseProps = Omit<React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, 'value'> & InputOnFocusProps;
package/index.esm.js CHANGED
@@ -288,7 +288,8 @@ const Text = (props) => {
288
288
  });
289
289
  return React.createElement(tagChoice, {
290
290
  style: style,
291
- className: cx('text', styles, props.className)
291
+ className: cx('text', styles, props.className),
292
+ id: props.id
292
293
  }, props.children);
293
294
  };
294
295
 
@@ -949,7 +950,7 @@ const ListItem = (props) => {
949
950
 
950
951
  const TabLocker = (props) => {
951
952
  const tabLocker = React.useRef(null);
952
- return (React.createElement("div", { className: "tabLocker", style: props.style, ref: tabLocker, onKeyDown: e => {
953
+ return (React.createElement("div", { className: cx('tabLocker', props.className), style: props.style, ref: tabLocker, onKeyDown: e => {
953
954
  var _a, _b;
954
955
  if (props.disabled) {
955
956
  return;
@@ -1662,7 +1663,7 @@ const Modal = (p) => {
1662
1663
  const backdrop = useBackdropContext();
1663
1664
  const mouseDownElement = useRef(undefined);
1664
1665
  const theme = useThemeSafely();
1665
- const hasHeader = p.closeButton || p.heading;
1666
+ const hasHeader = !p.__noHeader;
1666
1667
  const contentRef = React__default.useRef(null);
1667
1668
  const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
1668
1669
  const showing = useRef(p.show);
@@ -1701,10 +1702,22 @@ const Modal = (p) => {
1701
1702
  }
1702
1703
  };
1703
1704
  const zIndex = theme.zIndexes.modal;
1705
+ const { getText, language } = useLocalization();
1706
+ const closeText = React__default.useMemo(() => {
1707
+ return getText('Close');
1708
+ }, [language]);
1704
1709
  useEffect(() => {
1705
1710
  log('mounted');
1711
+ const escapeRemover = createBodyEscapeHandler(() => {
1712
+ if (showing.current) {
1713
+ p.onClose();
1714
+ }
1715
+ });
1716
+ log('body escape handler created');
1706
1717
  return () => {
1707
1718
  var _a;
1719
+ escapeRemover();
1720
+ log('body escape handler removed');
1708
1721
  if (showing.current) {
1709
1722
  log(`un-mount in progress and this modal is showing. decrement the backdrop and try to remove singleton body styles.`);
1710
1723
  backdrop.setShow(false, { key: (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', zIndex });
@@ -1751,9 +1764,9 @@ const Modal = (p) => {
1751
1764
  zIndex,
1752
1765
  cursor: 'default',
1753
1766
  margin: '1rem',
1754
- backgroundColor: p.noBackground ? undefined : theme.colors.modalBg,
1755
- border: p.noBackground ? undefined : theme.controls.border,
1756
- boxShadow: p.noBackground ? undefined : theme.controls.boxShadow,
1767
+ backgroundColor: !hasHeader ? undefined : theme.colors.modalBg,
1768
+ border: !hasHeader ? undefined : theme.controls.border,
1769
+ boxShadow: !hasHeader ? undefined : theme.controls.boxShadow,
1757
1770
  maxWidth: (_c = p.maxWidth) !== null && _c !== void 0 ? _c : theme.breakpoints.tablet,
1758
1771
  minWidth: (_d = p.minWidth) !== null && _d !== void 0 ? _d : (hasHeader ? '250px' : undefined),
1759
1772
  opacity: p.show ? 1 : 0,
@@ -1780,26 +1793,30 @@ const Modal = (p) => {
1780
1793
  display: 'flex',
1781
1794
  justifyContent: 'center',
1782
1795
  alignItems: 'center',
1783
- cursor: p.onClick ? 'pointer' : 'default'
1796
+ cursor: 'pointer'
1784
1797
  }, p.scrollable && {
1785
1798
  overflowY: 'auto',
1786
1799
  overflowX: 'hidden',
1787
1800
  alignItems: 'flex-start'
1788
1801
  }]);
1802
+ const ariaLabelId = `${p.id}_label`;
1789
1803
  if (p.show) {
1790
1804
  const backdropContainer = document.getElementById(backdrop.portalId);
1791
1805
  if (backdropContainer) {
1792
- return createPortal((React__default.createElement("div", { onClick: e => {
1806
+ return createPortal((React__default.createElement("div", { id: p.id, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
1793
1807
  e.stopPropagation();
1794
1808
  if (!mouseDownElement.current) {
1795
- if (p.onClick) {
1796
- log('backdropContainer onClick');
1797
- p.onClick();
1798
- }
1809
+ log('backdropContainer onClick');
1810
+ p.onClose();
1799
1811
  }
1800
1812
  mouseDownElement.current = undefined;
1813
+ }, onKeyDown: e => {
1814
+ if (e.code === 'Escape') {
1815
+ e.stopPropagation();
1816
+ p.onClose();
1817
+ }
1801
1818
  }, className: cx('modalContainer', modalContainerStyles) },
1802
- React__default.createElement("div", { id: p.id, ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
1819
+ React__default.createElement("div", { ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
1803
1820
  mouseDownElement.current = e.target;
1804
1821
  e.stopPropagation();
1805
1822
  }, onMouseUp: () => {
@@ -1813,21 +1830,35 @@ const Modal = (p) => {
1813
1830
  }, className: cx('modalBody', modalBodyStyles, p.className) },
1814
1831
  React__default.createElement(TabLocker, null,
1815
1832
  hasHeader && (React__default.createElement("header", { className: cx('modalHeader', modalHeaderStyles) },
1816
- p.heading ? React__default.createElement(Text, { className: css({
1833
+ React__default.createElement(Text, { id: ariaLabelId, className: css({
1817
1834
  margin: 0,
1818
1835
  flexGrow: 1
1819
- }), tag: "h1", bold: true }, p.heading) : React__default.createElement("span", null),
1820
- p.closeButton && p.onClick ? React__default.createElement(Button, { className: cx('modalCloseButton', css({
1836
+ }), tag: "h1", bold: true }, p.heading),
1837
+ React__default.createElement(Button, { className: cx('modalCloseButton', css({
1821
1838
  color: theme.colors.headerFont,
1822
1839
  marginLeft: '1rem',
1823
1840
  backgroundColor: 'transparent'
1824
- })), "aria-label": "Close", variant: "icon", onClick: p.onClick },
1825
- React__default.createElement(Icon, { id: "close" })) : React__default.createElement("span", null))),
1841
+ })), "aria-label": closeText, variant: "icon", onClick: e => {
1842
+ e.stopPropagation();
1843
+ p.onClose();
1844
+ } },
1845
+ React__default.createElement(Icon, { id: "close" })))),
1826
1846
  p.children)))), backdropContainer);
1827
1847
  }
1828
1848
  }
1829
1849
  return null;
1830
1850
  };
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
+ }
1831
1862
 
1832
1863
  const ConfirmModal = (props) => {
1833
1864
  const theme = useThemeSafely();
@@ -1845,7 +1876,7 @@ const ConfirmModal = (props) => {
1845
1876
  const cancelText = props.cancelText || getText('Cancel');
1846
1877
  return { confirmText, cancelText };
1847
1878
  }, [language, props.confirmText, props.cancelText]);
1848
- return (React.createElement(Modal, { id: props.id, __debug: props.__debug, className: cx('confirmModal', modalStyle, props.className), heading: props.header, closeButton: true, show: props.show, onClick: props.onCancel },
1879
+ return (React.createElement(Modal, { id: props.id, __debug: props.__debug, className: cx('confirmModal', modalStyle, props.className), heading: props.header, show: props.show, onClose: props.onCancel },
1849
1880
  React.createElement("div", { className: css({ padding: '1rem' }) },
1850
1881
  React.createElement(Text, { align: "center" }, props.text),
1851
1882
  React.createElement("div", { className: css({ textAlign: 'center' }) },
@@ -1909,7 +1940,7 @@ const ErrorModal = (props) => {
1909
1940
  color: ${theme.colors.omgFont};
1910
1941
  }
1911
1942
  `;
1912
- return (React.createElement(Modal, { id: props.id, __debug: props.__debug, className: cx('errorModal', modalStyles), heading: heading, closeButton: true, show: props.show, onClick: props.close },
1943
+ return (React.createElement(Modal, { id: props.id, __debug: props.__debug, className: cx('errorModal', modalStyles), heading: heading, show: props.show, onClose: props.onClose },
1913
1944
  React.createElement("div", { className: css({ padding: '1rem' }) },
1914
1945
  React.createElement(Text, { align: "center" }, message))));
1915
1946
  };
@@ -2381,6 +2412,10 @@ const InfoTip = (props) => {
2381
2412
  var _a, _b, _c;
2382
2413
  const [showTip, setShowTip] = React.useState(false);
2383
2414
  const theme = useThemeSafely();
2415
+ if (props.variant === 'modal' && !props.modalProps) {
2416
+ console.warn(`InfoTip with variant=modal requires modalProps.`);
2417
+ return null;
2418
+ }
2384
2419
  const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
2385
2420
  const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
2386
2421
  const onClick = () => {
@@ -2437,12 +2472,12 @@ const InfoTip = (props) => {
2437
2472
  display:inline-block;
2438
2473
  `;
2439
2474
  const button = React.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
2440
- if (props.variant === 'modal') {
2475
+ if (props.variant === 'modal' && props.modalProps) {
2441
2476
  return (React.createElement(React.Fragment, null,
2442
2477
  button,
2443
- React.createElement(Modal, { id: props.modalId, __debug: props.__modalDebug, show: showTip, heading: props.modalHeader, onClick: closeTip, className: css({
2478
+ React.createElement(Modal, { id: props.modalProps.id, __debug: props.modalProps.__debug, show: showTip, heading: props.modalProps.heading, onClose: closeTip, className: css({
2444
2479
  whiteSpace: 'normal'
2445
- }), closeButton: true },
2480
+ }) },
2446
2481
  React.createElement("div", { className: css({ padding: '1rem' }) }, props.content))));
2447
2482
  }
2448
2483
  else {
@@ -2848,6 +2883,7 @@ const Nav = (props) => {
2848
2883
  padding-top:0;
2849
2884
  `;
2850
2885
  React.useEffect(() => {
2886
+ console.log('useEffect');
2851
2887
  if (!backdrop.showing) {
2852
2888
  props.toggle(false);
2853
2889
  }
@@ -2858,10 +2894,16 @@ const Nav = (props) => {
2858
2894
  backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
2859
2895
  }, props.show);
2860
2896
  React.useLayoutEffect(() => {
2897
+ console.log('useLayoutEffect');
2861
2898
  if (nav && nav.current) {
2862
2899
  if (props.show) {
2863
2900
  if (!nav.current.classList.contains(classNavShowing)) {
2864
2901
  nav.current.classList.add(classNavShowing);
2902
+ setTimeout(() => {
2903
+ 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');
2906
+ }, slideMs + 1);
2865
2907
  }
2866
2908
  }
2867
2909
  else {
@@ -2877,7 +2919,12 @@ const Nav = (props) => {
2877
2919
  }
2878
2920
  }
2879
2921
  });
2880
- return (React.createElement("nav", { ref: nav, className: cx('nav', navStyles, props.className) }, props.children));
2922
+ return (React.createElement("nav", { role: "dialog", "aria-modal": "true", "aria-label": props.ariaLabel, ref: nav, className: cx('nav', navStyles, props.className), onKeyDown: e => {
2923
+ if (e.code === 'Escape') {
2924
+ props.toggle(false);
2925
+ }
2926
+ } },
2927
+ React.createElement(TabLocker, { className: css({ height: '100%' }) }, props.children)));
2881
2928
  };
2882
2929
 
2883
2930
  const LinkContent = (props) => {
@@ -4430,7 +4477,7 @@ const TogglePasswordInput = React.forwardRef((props, ref) => {
4430
4477
  });
4431
4478
 
4432
4479
  const WaitingIndicator = (p) => {
4433
- var _a, _b;
4480
+ var _a, _b, _c;
4434
4481
  const [show, setShow] = useState(p.show);
4435
4482
  const hideTimer = useRef(0);
4436
4483
  const lastShowStatus = useRef(false);
@@ -4482,7 +4529,10 @@ const WaitingIndicator = (p) => {
4482
4529
  }
4483
4530
  }
4484
4531
  }, [p.show]);
4485
- return (React__default.createElement(Modal, { id: p.id, __debug: p.__debug, className: "waitingIndicator", show: show, noBackground: true },
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: () => {
4534
+ /* noop */
4535
+ }, className: "waitingIndicator", show: show },
4486
4536
  React__default.createElement("div", { className: css({
4487
4537
  color: 'white',
4488
4538
  fontSize: '3rem',
package/index.js CHANGED
@@ -306,7 +306,8 @@ const Text = (props) => {
306
306
  });
307
307
  return React__namespace.createElement(tagChoice, {
308
308
  style: style,
309
- className: css.cx('text', styles, props.className)
309
+ className: css.cx('text', styles, props.className),
310
+ id: props.id
310
311
  }, props.children);
311
312
  };
312
313
 
@@ -967,7 +968,7 @@ const ListItem = (props) => {
967
968
 
968
969
  const TabLocker = (props) => {
969
970
  const tabLocker = React__namespace.useRef(null);
970
- return (React__namespace.createElement("div", { className: "tabLocker", style: props.style, ref: tabLocker, onKeyDown: e => {
971
+ return (React__namespace.createElement("div", { className: css.cx('tabLocker', props.className), style: props.style, ref: tabLocker, onKeyDown: e => {
971
972
  var _a, _b;
972
973
  if (props.disabled) {
973
974
  return;
@@ -1680,7 +1681,7 @@ const Modal = (p) => {
1680
1681
  const backdrop = useBackdropContext();
1681
1682
  const mouseDownElement = React.useRef(undefined);
1682
1683
  const theme = useThemeSafely();
1683
- const hasHeader = p.closeButton || p.heading;
1684
+ const hasHeader = !p.__noHeader;
1684
1685
  const contentRef = React.useRef(null);
1685
1686
  const log = useLogger((_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
1686
1687
  const showing = React.useRef(p.show);
@@ -1719,10 +1720,22 @@ const Modal = (p) => {
1719
1720
  }
1720
1721
  };
1721
1722
  const zIndex = theme.zIndexes.modal;
1723
+ const { getText, language } = useLocalization();
1724
+ const closeText = React.useMemo(() => {
1725
+ return getText('Close');
1726
+ }, [language]);
1722
1727
  React.useEffect(() => {
1723
1728
  log('mounted');
1729
+ const escapeRemover = createBodyEscapeHandler(() => {
1730
+ if (showing.current) {
1731
+ p.onClose();
1732
+ }
1733
+ });
1734
+ log('body escape handler created');
1724
1735
  return () => {
1725
1736
  var _a;
1737
+ escapeRemover();
1738
+ log('body escape handler removed');
1726
1739
  if (showing.current) {
1727
1740
  log(`un-mount in progress and this modal is showing. decrement the backdrop and try to remove singleton body styles.`);
1728
1741
  backdrop.setShow(false, { key: (_a = p.id) !== null && _a !== void 0 ? _a : 'Modal', zIndex });
@@ -1769,9 +1782,9 @@ const Modal = (p) => {
1769
1782
  zIndex,
1770
1783
  cursor: 'default',
1771
1784
  margin: '1rem',
1772
- backgroundColor: p.noBackground ? undefined : theme.colors.modalBg,
1773
- border: p.noBackground ? undefined : theme.controls.border,
1774
- boxShadow: p.noBackground ? undefined : theme.controls.boxShadow,
1785
+ backgroundColor: !hasHeader ? undefined : theme.colors.modalBg,
1786
+ border: !hasHeader ? undefined : theme.controls.border,
1787
+ boxShadow: !hasHeader ? undefined : theme.controls.boxShadow,
1775
1788
  maxWidth: (_c = p.maxWidth) !== null && _c !== void 0 ? _c : theme.breakpoints.tablet,
1776
1789
  minWidth: (_d = p.minWidth) !== null && _d !== void 0 ? _d : (hasHeader ? '250px' : undefined),
1777
1790
  opacity: p.show ? 1 : 0,
@@ -1798,26 +1811,30 @@ const Modal = (p) => {
1798
1811
  display: 'flex',
1799
1812
  justifyContent: 'center',
1800
1813
  alignItems: 'center',
1801
- cursor: p.onClick ? 'pointer' : 'default'
1814
+ cursor: 'pointer'
1802
1815
  }, p.scrollable && {
1803
1816
  overflowY: 'auto',
1804
1817
  overflowX: 'hidden',
1805
1818
  alignItems: 'flex-start'
1806
1819
  }]);
1820
+ const ariaLabelId = `${p.id}_label`;
1807
1821
  if (p.show) {
1808
1822
  const backdropContainer = document.getElementById(backdrop.portalId);
1809
1823
  if (backdropContainer) {
1810
- return reactDom.createPortal((React.createElement("div", { onClick: e => {
1824
+ return reactDom.createPortal((React.createElement("div", { id: p.id, role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelId, onClick: e => {
1811
1825
  e.stopPropagation();
1812
1826
  if (!mouseDownElement.current) {
1813
- if (p.onClick) {
1814
- log('backdropContainer onClick');
1815
- p.onClick();
1816
- }
1827
+ log('backdropContainer onClick');
1828
+ p.onClose();
1817
1829
  }
1818
1830
  mouseDownElement.current = undefined;
1831
+ }, onKeyDown: e => {
1832
+ if (e.code === 'Escape') {
1833
+ e.stopPropagation();
1834
+ p.onClose();
1835
+ }
1819
1836
  }, className: css.cx('modalContainer', modalContainerStyles) },
1820
- React.createElement("div", { id: p.id, ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
1837
+ React.createElement("div", { ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
1821
1838
  mouseDownElement.current = e.target;
1822
1839
  e.stopPropagation();
1823
1840
  }, onMouseUp: () => {
@@ -1831,21 +1848,35 @@ const Modal = (p) => {
1831
1848
  }, className: css.cx('modalBody', modalBodyStyles, p.className) },
1832
1849
  React.createElement(TabLocker, null,
1833
1850
  hasHeader && (React.createElement("header", { className: css.cx('modalHeader', modalHeaderStyles) },
1834
- p.heading ? React.createElement(Text, { className: css.css({
1851
+ React.createElement(Text, { id: ariaLabelId, className: css.css({
1835
1852
  margin: 0,
1836
1853
  flexGrow: 1
1837
- }), tag: "h1", bold: true }, p.heading) : React.createElement("span", null),
1838
- p.closeButton && p.onClick ? React.createElement(Button, { className: css.cx('modalCloseButton', css.css({
1854
+ }), tag: "h1", bold: true }, p.heading),
1855
+ React.createElement(Button, { className: css.cx('modalCloseButton', css.css({
1839
1856
  color: theme.colors.headerFont,
1840
1857
  marginLeft: '1rem',
1841
1858
  backgroundColor: 'transparent'
1842
- })), "aria-label": "Close", variant: "icon", onClick: p.onClick },
1843
- React.createElement(Icon, { id: "close" })) : React.createElement("span", null))),
1859
+ })), "aria-label": closeText, variant: "icon", onClick: e => {
1860
+ e.stopPropagation();
1861
+ p.onClose();
1862
+ } },
1863
+ React.createElement(Icon, { id: "close" })))),
1844
1864
  p.children)))), backdropContainer);
1845
1865
  }
1846
1866
  }
1847
1867
  return null;
1848
1868
  };
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
+ }
1849
1880
 
1850
1881
  const ConfirmModal = (props) => {
1851
1882
  const theme = useThemeSafely();
@@ -1863,7 +1894,7 @@ const ConfirmModal = (props) => {
1863
1894
  const cancelText = props.cancelText || getText('Cancel');
1864
1895
  return { confirmText, cancelText };
1865
1896
  }, [language, props.confirmText, props.cancelText]);
1866
- return (React__namespace.createElement(Modal, { id: props.id, __debug: props.__debug, className: css.cx('confirmModal', modalStyle, props.className), heading: props.header, closeButton: true, show: props.show, onClick: props.onCancel },
1897
+ return (React__namespace.createElement(Modal, { id: props.id, __debug: props.__debug, className: css.cx('confirmModal', modalStyle, props.className), heading: props.header, show: props.show, onClose: props.onCancel },
1867
1898
  React__namespace.createElement("div", { className: css.css({ padding: '1rem' }) },
1868
1899
  React__namespace.createElement(Text, { align: "center" }, props.text),
1869
1900
  React__namespace.createElement("div", { className: css.css({ textAlign: 'center' }) },
@@ -1927,7 +1958,7 @@ const ErrorModal = (props) => {
1927
1958
  color: ${theme.colors.omgFont};
1928
1959
  }
1929
1960
  `;
1930
- return (React__namespace.createElement(Modal, { id: props.id, __debug: props.__debug, className: css.cx('errorModal', modalStyles), heading: heading, closeButton: true, show: props.show, onClick: props.close },
1961
+ return (React__namespace.createElement(Modal, { id: props.id, __debug: props.__debug, className: css.cx('errorModal', modalStyles), heading: heading, show: props.show, onClose: props.onClose },
1931
1962
  React__namespace.createElement("div", { className: css.css({ padding: '1rem' }) },
1932
1963
  React__namespace.createElement(Text, { align: "center" }, message))));
1933
1964
  };
@@ -2399,6 +2430,10 @@ const InfoTip = (props) => {
2399
2430
  var _a, _b, _c;
2400
2431
  const [showTip, setShowTip] = React__namespace.useState(false);
2401
2432
  const theme = useThemeSafely();
2433
+ if (props.variant === 'modal' && !props.modalProps) {
2434
+ console.warn(`InfoTip with variant=modal requires modalProps.`);
2435
+ return null;
2436
+ }
2402
2437
  const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
2403
2438
  const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
2404
2439
  const onClick = () => {
@@ -2455,12 +2490,12 @@ const InfoTip = (props) => {
2455
2490
  display:inline-block;
2456
2491
  `;
2457
2492
  const button = React__namespace.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
2458
- if (props.variant === 'modal') {
2493
+ if (props.variant === 'modal' && props.modalProps) {
2459
2494
  return (React__namespace.createElement(React__namespace.Fragment, null,
2460
2495
  button,
2461
- React__namespace.createElement(Modal, { id: props.modalId, __debug: props.__modalDebug, show: showTip, heading: props.modalHeader, onClick: closeTip, className: css.css({
2496
+ React__namespace.createElement(Modal, { id: props.modalProps.id, __debug: props.modalProps.__debug, show: showTip, heading: props.modalProps.heading, onClose: closeTip, className: css.css({
2462
2497
  whiteSpace: 'normal'
2463
- }), closeButton: true },
2498
+ }) },
2464
2499
  React__namespace.createElement("div", { className: css.css({ padding: '1rem' }) }, props.content))));
2465
2500
  }
2466
2501
  else {
@@ -2866,6 +2901,7 @@ const Nav = (props) => {
2866
2901
  padding-top:0;
2867
2902
  `;
2868
2903
  React__namespace.useEffect(() => {
2904
+ console.log('useEffect');
2869
2905
  if (!backdrop.showing) {
2870
2906
  props.toggle(false);
2871
2907
  }
@@ -2876,10 +2912,16 @@ const Nav = (props) => {
2876
2912
  backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
2877
2913
  }, props.show);
2878
2914
  React__namespace.useLayoutEffect(() => {
2915
+ console.log('useLayoutEffect');
2879
2916
  if (nav && nav.current) {
2880
2917
  if (props.show) {
2881
2918
  if (!nav.current.classList.contains(classNavShowing)) {
2882
2919
  nav.current.classList.add(classNavShowing);
2920
+ setTimeout(() => {
2921
+ 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');
2924
+ }, slideMs + 1);
2883
2925
  }
2884
2926
  }
2885
2927
  else {
@@ -2895,7 +2937,12 @@ const Nav = (props) => {
2895
2937
  }
2896
2938
  }
2897
2939
  });
2898
- return (React__namespace.createElement("nav", { ref: nav, className: css.cx('nav', navStyles, props.className) }, props.children));
2940
+ return (React__namespace.createElement("nav", { role: "dialog", "aria-modal": "true", "aria-label": props.ariaLabel, ref: nav, className: css.cx('nav', navStyles, props.className), onKeyDown: e => {
2941
+ if (e.code === 'Escape') {
2942
+ props.toggle(false);
2943
+ }
2944
+ } },
2945
+ React__namespace.createElement(TabLocker, { className: css.css({ height: '100%' }) }, props.children)));
2899
2946
  };
2900
2947
 
2901
2948
  const LinkContent = (props) => {
@@ -4448,7 +4495,7 @@ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
4448
4495
  });
4449
4496
 
4450
4497
  const WaitingIndicator = (p) => {
4451
- var _a, _b;
4498
+ var _a, _b, _c;
4452
4499
  const [show, setShow] = React.useState(p.show);
4453
4500
  const hideTimer = React.useRef(0);
4454
4501
  const lastShowStatus = React.useRef(false);
@@ -4500,7 +4547,10 @@ const WaitingIndicator = (p) => {
4500
4547
  }
4501
4548
  }
4502
4549
  }, [p.show]);
4503
- return (React.createElement(Modal, { id: p.id, __debug: p.__debug, className: "waitingIndicator", show: show, noBackground: true },
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: () => {
4552
+ /* noop */
4553
+ }, className: "waitingIndicator", show: show },
4504
4554
  React.createElement("div", { className: css.css({
4505
4555
  color: 'white',
4506
4556
  fontSize: '3rem',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mackin.com/styleguide",
3
- "version": "11.0.1",
3
+ "version": "11.0.2",
4
4
  "description": "",
5
5
  "main": "./index.js",
6
6
  "module": "./index.esm.js",