@mackin.com/styleguide 11.0.6 → 11.0.8

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 +13 -10
  2. package/index.esm.js +108 -40
  3. package/index.js +109 -41
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import React__default, { ReactNode } from 'react';
4
4
  import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
5
5
 
6
6
  type HeaderVariant = 'label' | 'link' | 'primary' | 'secondary' | 'omg' | 'primary2' | 'positive' | 'negative';
7
- interface AccordianProps {
7
+ interface AccordionProps {
8
8
  /** Required for ARIA. */
9
9
  id: string;
10
10
  header: JSX.Element | string;
@@ -12,24 +12,25 @@ interface AccordianProps {
12
12
  variant?: HeaderVariant;
13
13
  /** Defaults to 'true'. */
14
14
  block?: boolean;
15
- className?: string;
15
+ /** Applied to the outer wrapping `DIV`. */
16
+ wrapperClassName?: string;
17
+ /** Applied to the expand/collapse header button. */
18
+ headerButtonClassName?: string;
16
19
  /** If true, padding will not be added to the expanded content */
17
20
  noPad?: boolean;
18
- /** The initial state of the Accordian. Defaults to 'false'.
19
- * Use with onChange to control the state from outside the Accordian.
21
+ /** The initial state of the Accordion. Defaults to 'false'.
22
+ * Use with onChange to control the state from outside the Accordion.
20
23
  */
21
24
  open?: boolean;
22
25
  disabled?: boolean;
23
- /** Defaults to 1020px. */
24
- maxHeight?: string | undefined;
25
26
  /** Defaults to 250ms. */
26
27
  expandTimeMs?: number;
27
28
  /** Defaults to 'ease-in-out'. */
28
29
  transitionTimingFunction?: string;
29
30
  onChange?: (open: boolean) => void;
30
31
  }
31
- declare const Accordian: (props: AccordianProps) => React.JSX.Element;
32
- declare const useAccordianState: (count: number, openIndex?: number) => [boolean[], (index: number, open: boolean) => void];
32
+ declare const Accordion: (props: AccordionProps) => React.JSX.Element;
33
+ declare const useAccordionState: (count: number, openIndex?: number) => [boolean[], (index: number, open: boolean) => void];
33
34
 
34
35
  interface InputOnFocusProps {
35
36
  /** If true, the component will respond to outside changes even if the control has focus. Default is false. */
@@ -445,6 +446,8 @@ declare const Nav: (props: {
445
446
  slideMs?: number;
446
447
  /** Defaults to `theme.layout.navWidth`. */
447
448
  navWidth?: string;
449
+ /** The DOM ID of the element to focus when the nav closes. */
450
+ onCloseFocusId?: string;
448
451
  __debug?: boolean;
449
452
  }) => React.JSX.Element;
450
453
 
@@ -1229,10 +1232,10 @@ declare const LocalizationProvider: (p: {
1229
1232
  declare function useAriaLiveRegion(): {
1230
1233
  /**
1231
1234
  * @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`..
1235
+ * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`.
1233
1236
  */
1234
1237
  notify: (message: string, clearTimoutMs?: number) => void;
1235
1238
  clearNotification: () => void;
1236
1239
  };
1237
1240
 
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, type DialogPopoverProps, 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, type TooltipPopoverProps, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
1241
+ export { Accordion, type AccordionProps, 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, type DialogPopoverProps, 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, type TooltipPopoverProps, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordionState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
package/index.esm.js CHANGED
@@ -497,47 +497,68 @@ const Button = React.forwardRef((props, ref) => {
497
497
  return content;
498
498
  });
499
499
 
500
- const accordianExpandTimeMs = 250;
501
- const accordianMaxHeight = 1020;
502
- const accordianTimingFunction = 'ease-in-out';
503
- // we need to apply the seperately so stuff doesn't hang over during expand/collapse.
504
- // if we remove this and just keep overflow:hidden, autocompletes will get cut off in the subpanels.
505
- const visibleStyle = css({
506
- overflow: 'visible !important'
507
- });
508
- const Accordian = (props) => {
509
- var _a, _b, _c, _d;
500
+ const defaultExpandTimeMs = 250;
501
+ const timingFunction = 'ease-in-out';
502
+ const Accordion = (props) => {
503
+ var _a, _b, _c;
504
+ const ignoreTransitionCount = React.useRef(props.open === true ? 2 : 0);
510
505
  const [open, setOpen] = React.useState(false);
511
506
  const theme = useThemeSafely();
512
507
  const content = React.useRef(null);
513
- const [children, setChildren] = React.useState();
508
+ const expandTimeMs = (_a = props.expandTimeMs) !== null && _a !== void 0 ? _a : defaultExpandTimeMs;
514
509
  const contentStyles = css({
510
+ label: 'AccordionContent',
511
+ height: 0,
515
512
  overflow: 'hidden',
516
- maxHeight: 0,
517
- transition: `max-height ${(_a = props.expandTimeMs) !== null && _a !== void 0 ? _a : accordianExpandTimeMs}ms ${(_b = props.transitionTimingFunction) !== null && _b !== void 0 ? _b : accordianTimingFunction}`
518
- });
519
- const expandedContentStyles = css({
520
- maxHeight: (_c = props.maxHeight) !== null && _c !== void 0 ? _c : accordianMaxHeight
513
+ transition: `height ${expandTimeMs}ms ${(_b = props.transitionTimingFunction) !== null && _b !== void 0 ? _b : timingFunction}`,
514
+ visibility: 'hidden',
521
515
  });
522
516
  const expandedContentWrapperStyles = !props.noPad ? css({
517
+ label: 'AccordionWrapper',
523
518
  padding: '0 1rem 1rem 1rem'
524
519
  }) : undefined;
520
+ function forceBrowserReflow() {
521
+ var _a;
522
+ // accessing this prop will cause browser to reflow and allow for calculations
523
+ (_a = content.current) === null || _a === void 0 ? void 0 : _a.offsetHeight;
524
+ }
525
525
  React.useEffect(() => {
526
526
  const currentContent = content.current;
527
527
  if (currentContent) {
528
528
  if (open) {
529
- setChildren(props.children);
530
- currentContent.classList.add(expandedContentStyles);
531
- window.setTimeout(() => {
532
- currentContent.classList.add(visibleStyle);
533
- }, accordianExpandTimeMs);
529
+ currentContent.style.visibility = 'visible';
530
+ currentContent.style.height = '0px';
531
+ forceBrowserReflow();
532
+ if (ignoreTransitionCount.current) {
533
+ // set the height to a auto so content changes will causes re-size
534
+ currentContent.style.height = 'auto';
535
+ ignoreTransitionCount.current -= 1;
536
+ }
537
+ else {
538
+ // set the height so the CSS transitions take over
539
+ currentContent.style.height = `${currentContent.scrollHeight}px`;
540
+ setTimeout(() => {
541
+ // set the height to a auto so content changes will causes re-size
542
+ currentContent.style.height = 'auto';
543
+ }, expandTimeMs + 1);
544
+ }
534
545
  }
535
546
  else {
536
- currentContent.classList.remove(visibleStyle, expandedContentStyles);
537
- if (children !== undefined) {
538
- window.setTimeout(() => {
539
- setChildren(undefined);
540
- }, accordianExpandTimeMs);
547
+ // set the height back from 'auto' above.
548
+ currentContent.style.height = `${currentContent.scrollHeight}px`;
549
+ forceBrowserReflow();
550
+ // set the height so the CSS transitions take over
551
+ currentContent.style.height = '0px';
552
+ if (ignoreTransitionCount.current) {
553
+ // undo the style so the root class takes back over ('hidden')
554
+ currentContent.style.visibility = '';
555
+ ignoreTransitionCount.current -= 1;
556
+ }
557
+ else {
558
+ setTimeout(() => {
559
+ // undo the style so the root class takes back over ('hidden')
560
+ currentContent.style.visibility = '';
561
+ }, expandTimeMs + 1);
541
562
  }
542
563
  }
543
564
  }
@@ -552,22 +573,24 @@ const Accordian = (props) => {
552
573
  setOpen((_a = props.open) !== null && _a !== void 0 ? _a : false);
553
574
  }, [props.open]);
554
575
  const expandedPanelId = `${props.id}_expanded`;
555
- return (React.createElement("div", { id: props.id, className: "accordian" },
576
+ const buttonId = `${props.id}_button`;
577
+ return (React.createElement("div", { id: props.id, className: props.wrapperClassName },
556
578
  React.createElement("h3", { className: css({
557
579
  // required for ARIA
558
580
  margin: 0,
559
581
  padding: 0,
560
582
  fontSize: 'inherit'
561
583
  }) },
562
- React.createElement(Button, { "aria-controls": expandedPanelId, "aria-expanded": open, "aria-disabled": props.disabled, readOnly: props.disabled, variant: props.variant, className: cx(css({
584
+ React.createElement(Button, { id: buttonId, "aria-controls": expandedPanelId, "aria-expanded": open, "aria-disabled": props.disabled, readOnly: props.disabled, variant: props.variant, className: cx(css({
563
585
  display: 'flex',
564
586
  alignItems: 'center',
565
587
  justifyContent: 'space-between',
566
588
  height: 'auto',
567
589
  minHeight: theme.controls.height,
568
- width: ((_d = props.block) !== null && _d !== void 0 ? _d : true) ? '100%' : 'auto'
569
- }, props.className)), onClick: e => {
590
+ width: ((_c = props.block) !== null && _c !== void 0 ? _c : true) ? '100%' : 'auto'
591
+ }, props.headerButtonClassName)), onClick: e => {
570
592
  e.stopPropagation();
593
+ console.warn('click');
571
594
  if (props.onChange) {
572
595
  props.onChange(!open);
573
596
  }
@@ -576,10 +599,10 @@ const Accordian = (props) => {
576
599
  }
577
600
  }, rightIcon: !props.disabled ? React.createElement(Icon, { id: open ? 'collapse' : 'expand' }) : undefined },
578
601
  React.createElement("span", null, props.header))),
579
- React.createElement("div", { ref: content, className: cx('accordian__body', contentStyles) },
580
- React.createElement("div", { className: expandedContentWrapperStyles, id: expandedPanelId }, children))));
602
+ React.createElement("div", { ref: content, className: contentStyles },
603
+ React.createElement("div", { className: expandedContentWrapperStyles, id: expandedPanelId, hidden: !open, role: "region", "aria-labelledby": buttonId }, props.children))));
581
604
  };
582
- const useAccordianState = (count, openIndex) => {
605
+ const useAccordionState = (count, openIndex) => {
583
606
  const [panels, setShowPanel] = React.useState(new Array(count).fill(false).map((b, i) => {
584
607
  return i === openIndex;
585
608
  }));
@@ -958,8 +981,32 @@ const TabLocker = (props) => {
958
981
  if (e.key === 'Tab') {
959
982
  e.preventDefault();
960
983
  e.stopPropagation();
961
- const tabElements = Array.from((_b = (_a = tabLocker.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])')) !== null && _b !== void 0 ? _b : []).filter(el => !el.hasAttribute('disabled'));
962
- if (tabElements.length) {
984
+ let tabElements;
985
+ try {
986
+ tabElements = Array.from((_b = (_a = tabLocker.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(tabQuery)) !== null && _b !== void 0 ? _b : [])
987
+ .filter(el => {
988
+ if (el.hasAttribute('disabled')) {
989
+ // seems to be unreliable when done in the query itself
990
+ return false;
991
+ }
992
+ if (el.getAttribute('tabindex') === '-1') {
993
+ // '[tabindex]:not([tabindex="-1"])' is in the query, but is ignored for controls that can already
994
+ // receive focus like buttons. We'll leave it in because it DOSE ignore non-focus elements with a tabindex.
995
+ return false;
996
+ }
997
+ if (el.hasAttribute('hidden')) {
998
+ return false;
999
+ }
1000
+ if (el.closest('[hidden]')) {
1001
+ return false;
1002
+ }
1003
+ return true;
1004
+ });
1005
+ }
1006
+ catch (err) {
1007
+ console.error(err);
1008
+ }
1009
+ if (tabElements === null || tabElements === void 0 ? void 0 : tabElements.length) {
963
1010
  const direction = e.shiftKey ? -1 : 1;
964
1011
  const index = tabElements.findIndex(x => x === document.activeElement);
965
1012
  if (index === undefined) {
@@ -978,6 +1025,15 @@ const TabLocker = (props) => {
978
1025
  }
979
1026
  } }, props.children));
980
1027
  };
1028
+ // easier to look at!
1029
+ const tabQuery = [
1030
+ 'a',
1031
+ 'button',
1032
+ 'input',
1033
+ 'textarea',
1034
+ 'select',
1035
+ '[tabindex]:not([tabindex="-1"])'
1036
+ ].join(',');
981
1037
 
982
1038
  /*
983
1039
  ARIA info:
@@ -1123,8 +1179,13 @@ const Autocomplete = (p) => {
1123
1179
  break;
1124
1180
  }
1125
1181
  case 'Tab': {
1126
- onPickValue(p.value, false);
1127
- setSelectedResultIndex(-1);
1182
+ // if there are options showing - and whether or not you picked one -
1183
+ // Tab is supposed to "select" the current value in the box per ARIA.
1184
+ // the normal blur process should be allowed to continue.
1185
+ if (displayOptions.length) {
1186
+ onPickValue(p.value, false);
1187
+ setSelectedResultIndex(-1);
1188
+ }
1128
1189
  break;
1129
1190
  }
1130
1191
  }
@@ -2498,7 +2559,7 @@ const InfoTip = (props) => {
2498
2559
  font-family: serif;
2499
2560
  display:inline-block;
2500
2561
  `;
2501
- let onButtonBlur = props.variant.type === 'Info' ?
2562
+ const onButtonBlur = props.variant.type === 'Info' ?
2502
2563
  () => {
2503
2564
  closeTip();
2504
2565
  } :
@@ -2971,6 +3032,13 @@ const Nav = (props) => {
2971
3032
  var _a;
2972
3033
  log('show changed', `${previous !== null && previous !== void 0 ? previous : 'undefined'} > ${current}`);
2973
3034
  backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
3035
+ if (!props.show && props.onCloseFocusId) {
3036
+ const focusId = props.onCloseFocusId;
3037
+ setTimeout(() => {
3038
+ var _a;
3039
+ (_a = document.getElementById(focusId)) === null || _a === void 0 ? void 0 : _a.focus();
3040
+ }, 0);
3041
+ }
2974
3042
  }, props.show);
2975
3043
  React.useLayoutEffect(() => {
2976
3044
  if (nav && nav.current) {
@@ -4623,7 +4691,7 @@ function useAriaLiveRegion() {
4623
4691
  return {
4624
4692
  /**
4625
4693
  * @param message - The text to be read by the screen reader.
4626
- * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
4694
+ * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`.
4627
4695
  */
4628
4696
  notify: (message, clearTimoutMs) => {
4629
4697
  if (clearTimerId) {
@@ -5291,5 +5359,5 @@ const LocalizationProvider = (p) => {
5291
5359
  } }, p.children));
5292
5360
  };
5293
5361
 
5294
- export { Accordian, Autocomplete, AutocompleteController, AutocompleteEntityController, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, Calendar, Checkbox, ConfirmModal, CopyButton, DateInput, DialogPopover, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, ItemPager, Label, Link, List, ListItem, LocalizationProvider, Modal, Nav, NormalizeCss, NumberInput, OmniLink, PagedResult, Pager, Picker, ProgressBar, SearchBox, Slider, StyleGuideLanguage, TabContainer, TabHeader, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, TextInput, Th, ThSort, ThemeProvider, ThemeRenderer, ToggleButton, ToggleButtonGroup, TogglePasswordInput, TooltipPopover, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, modalScrollFixClassName, useAccordianState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
5362
+ export { Accordion, 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, useAccordionState, useAriaLiveRegion, useBooleanChanged, useIgnoreMount, useMediaQuery, useScrollbarSize, useThemeSafely, useWaiting };
5295
5363
  //# sourceMappingURL=index.esm.js.map
package/index.js CHANGED
@@ -515,47 +515,68 @@ const Button = React__namespace.forwardRef((props, ref) => {
515
515
  return content;
516
516
  });
517
517
 
518
- const accordianExpandTimeMs = 250;
519
- const accordianMaxHeight = 1020;
520
- const accordianTimingFunction = 'ease-in-out';
521
- // we need to apply the seperately so stuff doesn't hang over during expand/collapse.
522
- // if we remove this and just keep overflow:hidden, autocompletes will get cut off in the subpanels.
523
- const visibleStyle = css.css({
524
- overflow: 'visible !important'
525
- });
526
- const Accordian = (props) => {
527
- var _a, _b, _c, _d;
518
+ const defaultExpandTimeMs = 250;
519
+ const timingFunction = 'ease-in-out';
520
+ const Accordion = (props) => {
521
+ var _a, _b, _c;
522
+ const ignoreTransitionCount = React__namespace.useRef(props.open === true ? 2 : 0);
528
523
  const [open, setOpen] = React__namespace.useState(false);
529
524
  const theme = useThemeSafely();
530
525
  const content = React__namespace.useRef(null);
531
- const [children, setChildren] = React__namespace.useState();
526
+ const expandTimeMs = (_a = props.expandTimeMs) !== null && _a !== void 0 ? _a : defaultExpandTimeMs;
532
527
  const contentStyles = css.css({
528
+ label: 'AccordionContent',
529
+ height: 0,
533
530
  overflow: 'hidden',
534
- maxHeight: 0,
535
- transition: `max-height ${(_a = props.expandTimeMs) !== null && _a !== void 0 ? _a : accordianExpandTimeMs}ms ${(_b = props.transitionTimingFunction) !== null && _b !== void 0 ? _b : accordianTimingFunction}`
536
- });
537
- const expandedContentStyles = css.css({
538
- maxHeight: (_c = props.maxHeight) !== null && _c !== void 0 ? _c : accordianMaxHeight
531
+ transition: `height ${expandTimeMs}ms ${(_b = props.transitionTimingFunction) !== null && _b !== void 0 ? _b : timingFunction}`,
532
+ visibility: 'hidden',
539
533
  });
540
534
  const expandedContentWrapperStyles = !props.noPad ? css.css({
535
+ label: 'AccordionWrapper',
541
536
  padding: '0 1rem 1rem 1rem'
542
537
  }) : undefined;
538
+ function forceBrowserReflow() {
539
+ var _a;
540
+ // accessing this prop will cause browser to reflow and allow for calculations
541
+ (_a = content.current) === null || _a === void 0 ? void 0 : _a.offsetHeight;
542
+ }
543
543
  React__namespace.useEffect(() => {
544
544
  const currentContent = content.current;
545
545
  if (currentContent) {
546
546
  if (open) {
547
- setChildren(props.children);
548
- currentContent.classList.add(expandedContentStyles);
549
- window.setTimeout(() => {
550
- currentContent.classList.add(visibleStyle);
551
- }, accordianExpandTimeMs);
547
+ currentContent.style.visibility = 'visible';
548
+ currentContent.style.height = '0px';
549
+ forceBrowserReflow();
550
+ if (ignoreTransitionCount.current) {
551
+ // set the height to a auto so content changes will causes re-size
552
+ currentContent.style.height = 'auto';
553
+ ignoreTransitionCount.current -= 1;
554
+ }
555
+ else {
556
+ // set the height so the CSS transitions take over
557
+ currentContent.style.height = `${currentContent.scrollHeight}px`;
558
+ setTimeout(() => {
559
+ // set the height to a auto so content changes will causes re-size
560
+ currentContent.style.height = 'auto';
561
+ }, expandTimeMs + 1);
562
+ }
552
563
  }
553
564
  else {
554
- currentContent.classList.remove(visibleStyle, expandedContentStyles);
555
- if (children !== undefined) {
556
- window.setTimeout(() => {
557
- setChildren(undefined);
558
- }, accordianExpandTimeMs);
565
+ // set the height back from 'auto' above.
566
+ currentContent.style.height = `${currentContent.scrollHeight}px`;
567
+ forceBrowserReflow();
568
+ // set the height so the CSS transitions take over
569
+ currentContent.style.height = '0px';
570
+ if (ignoreTransitionCount.current) {
571
+ // undo the style so the root class takes back over ('hidden')
572
+ currentContent.style.visibility = '';
573
+ ignoreTransitionCount.current -= 1;
574
+ }
575
+ else {
576
+ setTimeout(() => {
577
+ // undo the style so the root class takes back over ('hidden')
578
+ currentContent.style.visibility = '';
579
+ }, expandTimeMs + 1);
559
580
  }
560
581
  }
561
582
  }
@@ -570,22 +591,24 @@ const Accordian = (props) => {
570
591
  setOpen((_a = props.open) !== null && _a !== void 0 ? _a : false);
571
592
  }, [props.open]);
572
593
  const expandedPanelId = `${props.id}_expanded`;
573
- return (React__namespace.createElement("div", { id: props.id, className: "accordian" },
594
+ const buttonId = `${props.id}_button`;
595
+ return (React__namespace.createElement("div", { id: props.id, className: props.wrapperClassName },
574
596
  React__namespace.createElement("h3", { className: css.css({
575
597
  // required for ARIA
576
598
  margin: 0,
577
599
  padding: 0,
578
600
  fontSize: 'inherit'
579
601
  }) },
580
- React__namespace.createElement(Button, { "aria-controls": expandedPanelId, "aria-expanded": open, "aria-disabled": props.disabled, readOnly: props.disabled, variant: props.variant, className: css.cx(css.css({
602
+ React__namespace.createElement(Button, { id: buttonId, "aria-controls": expandedPanelId, "aria-expanded": open, "aria-disabled": props.disabled, readOnly: props.disabled, variant: props.variant, className: css.cx(css.css({
581
603
  display: 'flex',
582
604
  alignItems: 'center',
583
605
  justifyContent: 'space-between',
584
606
  height: 'auto',
585
607
  minHeight: theme.controls.height,
586
- width: ((_d = props.block) !== null && _d !== void 0 ? _d : true) ? '100%' : 'auto'
587
- }, props.className)), onClick: e => {
608
+ width: ((_c = props.block) !== null && _c !== void 0 ? _c : true) ? '100%' : 'auto'
609
+ }, props.headerButtonClassName)), onClick: e => {
588
610
  e.stopPropagation();
611
+ console.warn('click');
589
612
  if (props.onChange) {
590
613
  props.onChange(!open);
591
614
  }
@@ -594,10 +617,10 @@ const Accordian = (props) => {
594
617
  }
595
618
  }, rightIcon: !props.disabled ? React__namespace.createElement(Icon, { id: open ? 'collapse' : 'expand' }) : undefined },
596
619
  React__namespace.createElement("span", null, props.header))),
597
- React__namespace.createElement("div", { ref: content, className: css.cx('accordian__body', contentStyles) },
598
- React__namespace.createElement("div", { className: expandedContentWrapperStyles, id: expandedPanelId }, children))));
620
+ React__namespace.createElement("div", { ref: content, className: contentStyles },
621
+ React__namespace.createElement("div", { className: expandedContentWrapperStyles, id: expandedPanelId, hidden: !open, role: "region", "aria-labelledby": buttonId }, props.children))));
599
622
  };
600
- const useAccordianState = (count, openIndex) => {
623
+ const useAccordionState = (count, openIndex) => {
601
624
  const [panels, setShowPanel] = React__namespace.useState(new Array(count).fill(false).map((b, i) => {
602
625
  return i === openIndex;
603
626
  }));
@@ -976,8 +999,32 @@ const TabLocker = (props) => {
976
999
  if (e.key === 'Tab') {
977
1000
  e.preventDefault();
978
1001
  e.stopPropagation();
979
- const tabElements = Array.from((_b = (_a = tabLocker.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])')) !== null && _b !== void 0 ? _b : []).filter(el => !el.hasAttribute('disabled'));
980
- if (tabElements.length) {
1002
+ let tabElements;
1003
+ try {
1004
+ tabElements = Array.from((_b = (_a = tabLocker.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(tabQuery)) !== null && _b !== void 0 ? _b : [])
1005
+ .filter(el => {
1006
+ if (el.hasAttribute('disabled')) {
1007
+ // seems to be unreliable when done in the query itself
1008
+ return false;
1009
+ }
1010
+ if (el.getAttribute('tabindex') === '-1') {
1011
+ // '[tabindex]:not([tabindex="-1"])' is in the query, but is ignored for controls that can already
1012
+ // receive focus like buttons. We'll leave it in because it DOSE ignore non-focus elements with a tabindex.
1013
+ return false;
1014
+ }
1015
+ if (el.hasAttribute('hidden')) {
1016
+ return false;
1017
+ }
1018
+ if (el.closest('[hidden]')) {
1019
+ return false;
1020
+ }
1021
+ return true;
1022
+ });
1023
+ }
1024
+ catch (err) {
1025
+ console.error(err);
1026
+ }
1027
+ if (tabElements === null || tabElements === void 0 ? void 0 : tabElements.length) {
981
1028
  const direction = e.shiftKey ? -1 : 1;
982
1029
  const index = tabElements.findIndex(x => x === document.activeElement);
983
1030
  if (index === undefined) {
@@ -996,6 +1043,15 @@ const TabLocker = (props) => {
996
1043
  }
997
1044
  } }, props.children));
998
1045
  };
1046
+ // easier to look at!
1047
+ const tabQuery = [
1048
+ 'a',
1049
+ 'button',
1050
+ 'input',
1051
+ 'textarea',
1052
+ 'select',
1053
+ '[tabindex]:not([tabindex="-1"])'
1054
+ ].join(',');
999
1055
 
1000
1056
  /*
1001
1057
  ARIA info:
@@ -1141,8 +1197,13 @@ const Autocomplete = (p) => {
1141
1197
  break;
1142
1198
  }
1143
1199
  case 'Tab': {
1144
- onPickValue(p.value, false);
1145
- setSelectedResultIndex(-1);
1200
+ // if there are options showing - and whether or not you picked one -
1201
+ // Tab is supposed to "select" the current value in the box per ARIA.
1202
+ // the normal blur process should be allowed to continue.
1203
+ if (displayOptions.length) {
1204
+ onPickValue(p.value, false);
1205
+ setSelectedResultIndex(-1);
1206
+ }
1146
1207
  break;
1147
1208
  }
1148
1209
  }
@@ -2516,7 +2577,7 @@ const InfoTip = (props) => {
2516
2577
  font-family: serif;
2517
2578
  display:inline-block;
2518
2579
  `;
2519
- let onButtonBlur = props.variant.type === 'Info' ?
2580
+ const onButtonBlur = props.variant.type === 'Info' ?
2520
2581
  () => {
2521
2582
  closeTip();
2522
2583
  } :
@@ -2989,6 +3050,13 @@ const Nav = (props) => {
2989
3050
  var _a;
2990
3051
  log('show changed', `${previous !== null && previous !== void 0 ? previous : 'undefined'} > ${current}`);
2991
3052
  backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
3053
+ if (!props.show && props.onCloseFocusId) {
3054
+ const focusId = props.onCloseFocusId;
3055
+ setTimeout(() => {
3056
+ var _a;
3057
+ (_a = document.getElementById(focusId)) === null || _a === void 0 ? void 0 : _a.focus();
3058
+ }, 0);
3059
+ }
2992
3060
  }, props.show);
2993
3061
  React__namespace.useLayoutEffect(() => {
2994
3062
  if (nav && nav.current) {
@@ -4641,7 +4709,7 @@ function useAriaLiveRegion() {
4641
4709
  return {
4642
4710
  /**
4643
4711
  * @param message - The text to be read by the screen reader.
4644
- * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`..
4712
+ * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`.
4645
4713
  */
4646
4714
  notify: (message, clearTimoutMs) => {
4647
4715
  if (clearTimerId) {
@@ -5309,7 +5377,7 @@ const LocalizationProvider = (p) => {
5309
5377
  } }, p.children));
5310
5378
  };
5311
5379
 
5312
- exports.Accordian = Accordian;
5380
+ exports.Accordion = Accordion;
5313
5381
  exports.Autocomplete = Autocomplete;
5314
5382
  exports.AutocompleteController = AutocompleteController;
5315
5383
  exports.AutocompleteEntityController = AutocompleteEntityController;
@@ -5381,7 +5449,7 @@ exports.enumToEntities = enumToEntities;
5381
5449
  exports.getCurrencyDisplay = getCurrencyDisplay;
5382
5450
  exports.getFileSizeDisplay = getFileSizeDisplay;
5383
5451
  exports.modalScrollFixClassName = modalScrollFixClassName;
5384
- exports.useAccordianState = useAccordianState;
5452
+ exports.useAccordionState = useAccordionState;
5385
5453
  exports.useAriaLiveRegion = useAriaLiveRegion;
5386
5454
  exports.useBooleanChanged = useBooleanChanged;
5387
5455
  exports.useIgnoreMount = useIgnoreMount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mackin.com/styleguide",
3
- "version": "11.0.6",
3
+ "version": "11.0.8",
4
4
  "description": "",
5
5
  "main": "./index.js",
6
6
  "module": "./index.esm.js",