@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.
- package/dist/charts.js +154 -1
- package/dist/charts.js.map +1 -1
- package/dist/charts.modern.module.js +154 -1
- package/dist/charts.modern.module.js.map +1 -1
- package/dist/charts.umd.js +606 -202
- package/dist/charts.umd.js.map +1 -1
- package/dist/hooks/useCarbonModalFocusManagement.d.ts +2 -0
- package/package.json +9 -4
- package/src/components/CarbonChart/CarbonChart.test.js +176 -1
- package/src/components/CarbonChart/CarbonChart.tsx +17 -1
- package/src/hooks/useCarbonModalFocusManagement.ts +173 -0
package/dist/charts.js
CHANGED
|
@@ -803,6 +803,148 @@ var curriedTransparentize = /*#__PURE__*/curry
|
|
|
803
803
|
/* ::<number | string, string, string> */
|
|
804
804
|
(transparentize);
|
|
805
805
|
|
|
806
|
+
var FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
807
|
+
function getFocusableElements(container) {
|
|
808
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) {
|
|
809
|
+
var style = window.getComputedStyle(el);
|
|
810
|
+
return (style.display !== 'none' &&
|
|
811
|
+
style.visibility !== 'hidden' &&
|
|
812
|
+
!el.hasAttribute('disabled'));
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
function findVisibleModal(wrapper) {
|
|
816
|
+
var modal = wrapper.querySelector('.cds--modal');
|
|
817
|
+
if (!modal)
|
|
818
|
+
return null;
|
|
819
|
+
var isVisible = modal.getAttribute('aria-modal') === 'true' ||
|
|
820
|
+
modal.style.visibility === 'visible' ||
|
|
821
|
+
modal.classList.contains('is-visible');
|
|
822
|
+
return isVisible ? modal : null;
|
|
823
|
+
}
|
|
824
|
+
function useCarbonModalFocusManagement(wrapperRef) {
|
|
825
|
+
var previouslyFocusedElement = React__namespace.useRef(null);
|
|
826
|
+
var keydownHandler = React__namespace.useRef(null);
|
|
827
|
+
var focusinHandler = React__namespace.useRef(null);
|
|
828
|
+
var currentModal = React__namespace.useRef(null);
|
|
829
|
+
React__namespace.useEffect(function () {
|
|
830
|
+
var wrapper = wrapperRef.current;
|
|
831
|
+
if (!wrapper)
|
|
832
|
+
return;
|
|
833
|
+
function focusModalCloseButton(modal) {
|
|
834
|
+
var closeButton = modal.querySelector('.cds--modal-close');
|
|
835
|
+
if (closeButton) {
|
|
836
|
+
closeButton.focus();
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
var focusable = getFocusableElements(modal);
|
|
840
|
+
if (focusable.length > 0) {
|
|
841
|
+
focusable[0].focus();
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function handleModalOpen(modal) {
|
|
846
|
+
currentModal.current = modal;
|
|
847
|
+
previouslyFocusedElement.current = document.activeElement;
|
|
848
|
+
// Permanent guard: redirect focus back into modal whenever it escapes
|
|
849
|
+
// (e.g. Carbon's overflow menu returning focus to its trigger).
|
|
850
|
+
focusinHandler.current = function (event) {
|
|
851
|
+
var target = event.target;
|
|
852
|
+
if (!modal.contains(target)) {
|
|
853
|
+
setTimeout(function () {
|
|
854
|
+
if (currentModal.current === modal) {
|
|
855
|
+
focusModalCloseButton(modal);
|
|
856
|
+
}
|
|
857
|
+
}, 0);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
document.addEventListener('focusin', focusinHandler.current);
|
|
861
|
+
var pollAttempts = 0;
|
|
862
|
+
var pollAndFocus = function () {
|
|
863
|
+
if (currentModal.current !== modal)
|
|
864
|
+
return;
|
|
865
|
+
if (modal.contains(document.activeElement))
|
|
866
|
+
return;
|
|
867
|
+
var closeBtn = modal.querySelector('.cds--modal-close');
|
|
868
|
+
if (closeBtn &&
|
|
869
|
+
window.getComputedStyle(closeBtn).visibility !== 'hidden') {
|
|
870
|
+
closeBtn.focus();
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (++pollAttempts < 30) {
|
|
874
|
+
requestAnimationFrame(pollAndFocus);
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
requestAnimationFrame(pollAndFocus);
|
|
878
|
+
keydownHandler.current = function (event) {
|
|
879
|
+
if (event.key !== 'Tab')
|
|
880
|
+
return;
|
|
881
|
+
var focusable = getFocusableElements(modal);
|
|
882
|
+
if (focusable.length === 0) {
|
|
883
|
+
event.preventDefault();
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
if (focusable.length === 1) {
|
|
887
|
+
event.preventDefault();
|
|
888
|
+
if (focusable[0] !== document.activeElement) {
|
|
889
|
+
focusable[0].focus();
|
|
890
|
+
}
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
var firstItem = focusable[0];
|
|
894
|
+
var lastItem = focusable[focusable.length - 1];
|
|
895
|
+
if (!event.shiftKey && document.activeElement === lastItem) {
|
|
896
|
+
event.preventDefault();
|
|
897
|
+
firstItem.focus();
|
|
898
|
+
}
|
|
899
|
+
else if (event.shiftKey && document.activeElement === firstItem) {
|
|
900
|
+
event.preventDefault();
|
|
901
|
+
lastItem.focus();
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
document.addEventListener('keydown', keydownHandler.current);
|
|
905
|
+
}
|
|
906
|
+
function handleModalClose() {
|
|
907
|
+
// Null out currentModal first so any pending setTimeout redirects
|
|
908
|
+
// (scheduled by the focusin guard) see a closed modal and bail out.
|
|
909
|
+
currentModal.current = null;
|
|
910
|
+
if (focusinHandler.current) {
|
|
911
|
+
document.removeEventListener('focusin', focusinHandler.current);
|
|
912
|
+
focusinHandler.current = null;
|
|
913
|
+
}
|
|
914
|
+
if (keydownHandler.current) {
|
|
915
|
+
document.removeEventListener('keydown', keydownHandler.current);
|
|
916
|
+
keydownHandler.current = null;
|
|
917
|
+
}
|
|
918
|
+
if (previouslyFocusedElement.current instanceof HTMLElement) {
|
|
919
|
+
previouslyFocusedElement.current.focus();
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
var observer = new MutationObserver(function () {
|
|
923
|
+
var visibleModal = findVisibleModal(wrapper);
|
|
924
|
+
if (visibleModal && !currentModal.current) {
|
|
925
|
+
handleModalOpen(visibleModal);
|
|
926
|
+
}
|
|
927
|
+
else if (!visibleModal && currentModal.current) {
|
|
928
|
+
handleModalClose();
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
observer.observe(wrapper, {
|
|
932
|
+
attributes: true,
|
|
933
|
+
attributeFilter: ['class', 'style', 'aria-modal'],
|
|
934
|
+
subtree: true,
|
|
935
|
+
});
|
|
936
|
+
return function () {
|
|
937
|
+
observer.disconnect();
|
|
938
|
+
if (keydownHandler.current) {
|
|
939
|
+
document.removeEventListener('keydown', keydownHandler.current);
|
|
940
|
+
}
|
|
941
|
+
if (focusinHandler.current) {
|
|
942
|
+
document.removeEventListener('focusin', focusinHandler.current);
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
}, [wrapperRef]);
|
|
946
|
+
}
|
|
947
|
+
|
|
806
948
|
function styleInject(css, ref) {
|
|
807
949
|
if ( ref === void 0 ) ref = {};
|
|
808
950
|
var insertAt = ref.insertAt;
|
|
@@ -1011,6 +1153,17 @@ var CarbonChart = React__namespace.forwardRef(function (props, ref) {
|
|
|
1011
1153
|
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"]);
|
|
1012
1154
|
var theme = React__namespace.useContext(reactMagmaDom.ThemeContext);
|
|
1013
1155
|
var isInverse = reactMagmaDom.useIsInverse(isInverseProp);
|
|
1156
|
+
var internalRef = React__namespace.useRef(null);
|
|
1157
|
+
var mergedRef = React__namespace.useCallback(function (node) {
|
|
1158
|
+
internalRef.current = node;
|
|
1159
|
+
if (typeof ref === 'function') {
|
|
1160
|
+
ref(node);
|
|
1161
|
+
}
|
|
1162
|
+
else if (ref) {
|
|
1163
|
+
ref.current = node;
|
|
1164
|
+
}
|
|
1165
|
+
}, [ref]);
|
|
1166
|
+
useCarbonModalFocusManagement(internalRef);
|
|
1014
1167
|
var allCharts = {
|
|
1015
1168
|
area: chartsReact.AreaChart,
|
|
1016
1169
|
areaStacked: chartsReact.StackedAreaChart,
|
|
@@ -1065,7 +1218,7 @@ var CarbonChart = React__namespace.forwardRef(function (props, ref) {
|
|
|
1065
1218
|
}
|
|
1066
1219
|
});
|
|
1067
1220
|
var groupsLength = Object.keys(buildColors()).length;
|
|
1068
|
-
return (React__namespace.createElement(CarbonChartWrapper, __assign({ "data-testid": testId, ref:
|
|
1221
|
+
return (React__namespace.createElement(CarbonChartWrapper, __assign({ "data-testid": testId, ref: mergedRef, isInverse: isInverse, theme: theme, className: "carbon-chart-wrapper", groupsLength: groupsLength < 6 ? groupsLength : 14 }, rest),
|
|
1069
1222
|
React__namespace.createElement(ChartType, { data: dataSet, options: newOptions })));
|
|
1070
1223
|
});
|
|
1071
1224
|
var templateObject_1;
|