@react-magma/charts 14.0.0-rc.3 → 14.0.0-rc.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.
@@ -782,6 +782,148 @@ var curriedTransparentize = /*#__PURE__*/curry
782
782
  /* ::<number | string, string, string> */
783
783
  (transparentize);
784
784
 
785
+ var FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
786
+ function getFocusableElements(container) {
787
+ return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) {
788
+ var style = window.getComputedStyle(el);
789
+ return (style.display !== 'none' &&
790
+ style.visibility !== 'hidden' &&
791
+ !el.hasAttribute('disabled'));
792
+ });
793
+ }
794
+ function findVisibleModal(wrapper) {
795
+ var modal = wrapper.querySelector('.cds--modal');
796
+ if (!modal)
797
+ return null;
798
+ var isVisible = modal.getAttribute('aria-modal') === 'true' ||
799
+ modal.style.visibility === 'visible' ||
800
+ modal.classList.contains('is-visible');
801
+ return isVisible ? modal : null;
802
+ }
803
+ function useCarbonModalFocusManagement(wrapperRef) {
804
+ var previouslyFocusedElement = React.useRef(null);
805
+ var keydownHandler = React.useRef(null);
806
+ var focusinHandler = React.useRef(null);
807
+ var currentModal = React.useRef(null);
808
+ React.useEffect(function () {
809
+ var wrapper = wrapperRef.current;
810
+ if (!wrapper)
811
+ return;
812
+ function focusModalCloseButton(modal) {
813
+ var closeButton = modal.querySelector('.cds--modal-close');
814
+ if (closeButton) {
815
+ closeButton.focus();
816
+ }
817
+ else {
818
+ var focusable = getFocusableElements(modal);
819
+ if (focusable.length > 0) {
820
+ focusable[0].focus();
821
+ }
822
+ }
823
+ }
824
+ function handleModalOpen(modal) {
825
+ currentModal.current = modal;
826
+ previouslyFocusedElement.current = document.activeElement;
827
+ // Permanent guard: redirect focus back into modal whenever it escapes
828
+ // (e.g. Carbon's overflow menu returning focus to its trigger).
829
+ focusinHandler.current = function (event) {
830
+ var target = event.target;
831
+ if (!modal.contains(target)) {
832
+ setTimeout(function () {
833
+ if (currentModal.current === modal) {
834
+ focusModalCloseButton(modal);
835
+ }
836
+ }, 0);
837
+ }
838
+ };
839
+ document.addEventListener('focusin', focusinHandler.current);
840
+ var pollAttempts = 0;
841
+ var pollAndFocus = function () {
842
+ if (currentModal.current !== modal)
843
+ return;
844
+ if (modal.contains(document.activeElement))
845
+ return;
846
+ var closeBtn = modal.querySelector('.cds--modal-close');
847
+ if (closeBtn &&
848
+ window.getComputedStyle(closeBtn).visibility !== 'hidden') {
849
+ closeBtn.focus();
850
+ return;
851
+ }
852
+ if (++pollAttempts < 30) {
853
+ requestAnimationFrame(pollAndFocus);
854
+ }
855
+ };
856
+ requestAnimationFrame(pollAndFocus);
857
+ keydownHandler.current = function (event) {
858
+ if (event.key !== 'Tab')
859
+ return;
860
+ var focusable = getFocusableElements(modal);
861
+ if (focusable.length === 0) {
862
+ event.preventDefault();
863
+ return;
864
+ }
865
+ if (focusable.length === 1) {
866
+ event.preventDefault();
867
+ if (focusable[0] !== document.activeElement) {
868
+ focusable[0].focus();
869
+ }
870
+ return;
871
+ }
872
+ var firstItem = focusable[0];
873
+ var lastItem = focusable[focusable.length - 1];
874
+ if (!event.shiftKey && document.activeElement === lastItem) {
875
+ event.preventDefault();
876
+ firstItem.focus();
877
+ }
878
+ else if (event.shiftKey && document.activeElement === firstItem) {
879
+ event.preventDefault();
880
+ lastItem.focus();
881
+ }
882
+ };
883
+ document.addEventListener('keydown', keydownHandler.current);
884
+ }
885
+ function handleModalClose() {
886
+ // Null out currentModal first so any pending setTimeout redirects
887
+ // (scheduled by the focusin guard) see a closed modal and bail out.
888
+ currentModal.current = null;
889
+ if (focusinHandler.current) {
890
+ document.removeEventListener('focusin', focusinHandler.current);
891
+ focusinHandler.current = null;
892
+ }
893
+ if (keydownHandler.current) {
894
+ document.removeEventListener('keydown', keydownHandler.current);
895
+ keydownHandler.current = null;
896
+ }
897
+ if (previouslyFocusedElement.current instanceof HTMLElement) {
898
+ previouslyFocusedElement.current.focus();
899
+ }
900
+ }
901
+ var observer = new MutationObserver(function () {
902
+ var visibleModal = findVisibleModal(wrapper);
903
+ if (visibleModal && !currentModal.current) {
904
+ handleModalOpen(visibleModal);
905
+ }
906
+ else if (!visibleModal && currentModal.current) {
907
+ handleModalClose();
908
+ }
909
+ });
910
+ observer.observe(wrapper, {
911
+ attributes: true,
912
+ attributeFilter: ['class', 'style', 'aria-modal'],
913
+ subtree: true,
914
+ });
915
+ return function () {
916
+ observer.disconnect();
917
+ if (keydownHandler.current) {
918
+ document.removeEventListener('keydown', keydownHandler.current);
919
+ }
920
+ if (focusinHandler.current) {
921
+ document.removeEventListener('focusin', focusinHandler.current);
922
+ }
923
+ };
924
+ }, [wrapperRef]);
925
+ }
926
+
785
927
  function styleInject(css, ref) {
786
928
  if ( ref === void 0 ) ref = {};
787
929
  var insertAt = ref.insertAt;
@@ -990,6 +1132,17 @@ var CarbonChart = React.forwardRef(function (props, ref) {
990
1132
  var testId = props.testId, isInverseProp = props.isInverse, type = props.type, dataSet = props.dataSet, options = props.options, ariaLabel = props.ariaLabel, rest = __rest(props, ["testId", "isInverse", "type", "dataSet", "options", "ariaLabel"]);
991
1133
  var theme = React.useContext(ThemeContext);
992
1134
  var isInverse = useIsInverse(isInverseProp);
1135
+ var internalRef = React.useRef(null);
1136
+ var mergedRef = React.useCallback(function (node) {
1137
+ internalRef.current = node;
1138
+ if (typeof ref === 'function') {
1139
+ ref(node);
1140
+ }
1141
+ else if (ref) {
1142
+ ref.current = node;
1143
+ }
1144
+ }, [ref]);
1145
+ useCarbonModalFocusManagement(internalRef);
993
1146
  var allCharts = {
994
1147
  area: AreaChart,
995
1148
  areaStacked: StackedAreaChart,
@@ -1044,7 +1197,7 @@ var CarbonChart = React.forwardRef(function (props, ref) {
1044
1197
  }
1045
1198
  });
1046
1199
  var groupsLength = Object.keys(buildColors()).length;
1047
- return (React.createElement(CarbonChartWrapper, __assign({ "data-testid": testId, ref: ref, isInverse: isInverse, theme: theme, className: "carbon-chart-wrapper", groupsLength: groupsLength < 6 ? groupsLength : 14 }, rest),
1200
+ return (React.createElement(CarbonChartWrapper, __assign({ "data-testid": testId, ref: mergedRef, isInverse: isInverse, theme: theme, className: "carbon-chart-wrapper", groupsLength: groupsLength < 6 ? groupsLength : 14 }, rest),
1048
1201
  React.createElement(ChartType, { data: dataSet, options: newOptions })));
1049
1202
  });
1050
1203
  var templateObject_1;