Skip to content

Commit

Permalink
STCOM-1238 Accordion vs overlay z-index issues. (#2240)
Browse files Browse the repository at this point in the history
* Accordions retain their z-index after being blurred, and assume the highest z-index when focus enters them.

* log changes

* remove unnecessary addition to z-index

* semi

* add comments to code
  • Loading branch information
JohnC-80 committed Mar 8, 2024
1 parent c5eab1d commit 4e1820a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .storybook/stcom-webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const { babelOptions } = require('@folio/stripes-cli');
const adjustedBabelOptions = Object.assign(babelOptions, { plugins: babelOptions.plugins.filter((p) => !p.includes('react-refresh')) });

module.exports = async (config) => {

config.devtool="eval-cheap-source-map";
// Replace Storybook's own CSS config
// get index of their css loading rule...
const cssRuleIndex = config.module.rules.findIndex(r => { const t = new RegExp(r.test); return t.test('m.css'); });
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Accessible grouping for filter group checkboxes via `role="group"`. Refs STCOM-1192.
* Fix `<FilterAccordionHeader>` does not have correct `aria-label` when `label` prop type is string. Fixes STCOM-1271.
* Add `number-generator` icon. Refs STCOM-1269.
* Accordions retain their z-index after being blurred, and assume the highest z-index when focus enters them. Refs STCOM-1238.

## [12.0.0](https://github.com/folio-org/stripes-components/tree/v12.0.0) (2023-10-11)
[Full Changelog](https://github.com/folio-org/stripes-components/compare/v11.0.0...v12.0.0)
Expand Down
45 changes: 41 additions & 4 deletions lib/Accordion/Accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ function getWrapClass(open) {
);
}

/* The z-index requirements for accordions:
* Accordions should not overlap any overlays/dropdowns from previous/next accordions.
* Accordions/overlays should not be overlapped if focus left the accordion or went to another pane...
*
*/

// loops through other accordions rendered within the UI to find the highest z-index among them all.
const getHighestStackOrder = () => {
const accordions = Array.from(document.querySelectorAll(`.${css['content-wrap']}`));
const highest = accordions?.reduce((acc, cur) => {
let currentZ = getComputedStyle(cur).getPropertyValue('z-index');
// skip any that might have non-integer z-index settings.
if (currentZ === 'auto' || currentZ === null) return acc;
currentZ = parseInt(currentZ, 10);
// this will prevent duplicated highest z-index, since with matching z-index, the tag
// that's ordered last will overlap.
if (currentZ === acc) currentZ += 1;
return currentZ > acc ? currentZ : acc;
}, 2);
return highest;
}

const Accordion = (props) => {
const {
accordionSet,
Expand Down Expand Up @@ -102,15 +124,29 @@ const Accordion = (props) => {
const getRef = useRef(() => toggle.current).current;
const [isOpen, updateOpen] = useState(open || !closedByDefault);
const [registered, updateRegistered] = useState(!accordionSet);
const [stackOrder, updateStackOrder] = useState(1);
const [zIndex, updateZIndex] = useState(1);
const [focused, updateFocused] = useState(false);

const uncontrolledToggle = useRef(() => {
updateOpen(current => !current);
}).current;

const handleFocusIn = () => updateZIndex(accordionSet?.getNumberOfAccordions() || 2);
const handleFocusOut = () => updateZIndex(stackOrder);
// Affecting z-index when accordions are focused within.
// We only update the accordion z-index if it does not contain focus _and_ if it's not
// already the highest z-index among other accordions.
const handleFocusIn = () => {
if (!focused) {
updateFocused(true);
const highest = getHighestStackOrder();
if (zIndex !== highest) {
updateZIndex(highest);
}
}
}

const handleFocusOut = () => {
updateFocused(false);
}

const onToggle = (toggleArgs) => {
if (typeof open === 'undefined') {
Expand All @@ -128,12 +164,13 @@ const Accordion = (props) => {
}
}, [open]);

// At registration, accordions are assigned a z-index that, in most cases,
// will render in reverse order.
useEffect(() => { // eslint-disable-line
function registrationCallback(isRegistered) {
updateRegistered(isRegistered);
if (accordionSet) {
const defaultZIndex = accordionSet.getStackOrder(trackingId);
updateStackOrder(defaultZIndex);
updateZIndex(defaultZIndex);
}
}
Expand Down

0 comments on commit 4e1820a

Please sign in to comment.