Skip to content

Commit

Permalink
STCOM-1341Change Repeatable fields component's focus behaviour (#2371)
Browse files Browse the repository at this point in the history
  • Loading branch information
vashjs authored Oct 23, 2024
1 parent b0ec277 commit ccdf147
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
* Export `<StripesOverlayWrapper>` that will automatically apply the `usePortal` behavior to nested overlay components. Refs STCOM-1353.
* Properly pass `readOnly` prop to `<RadioButton>`'s internally rendered `<Label>`. Refs STCOM-1367.
* `TextArea` - move focus to the field after clearing the field by clicking on the `x` icon. Refs STCOM-1369.
* Change `Repeatable field` focus behaviour. Refs STCOM-1341.

## [12.1.0](https://github.com/folio-org/stripes-components/tree/v12.1.0) (2024-03-12)
[Full Changelog](https://github.com/folio-org/stripes-components/compare/v12.0.0...v12.1.0)
Expand Down
12 changes: 10 additions & 2 deletions lib/RepeatableField/RepeatableField.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
Expand All @@ -11,6 +11,7 @@ import IconButton from '../IconButton';
import { RepeatableFieldContent } from "./RepeatableFieldContent";
import css from './RepeatableField.css';
import { useFocusedIndex } from "./hooks/useFocusedIndex";
import { useIsElementFocused } from "./hooks/useIsElementFocused";


const RepeatableField = ({
Expand All @@ -29,12 +30,16 @@ const RepeatableField = ({
onRemove,
renderField,
}) => {
const rootRef = useRef(null);
const showDeleteBtn = typeof onRemove === 'function';
const fieldsLength = fields.length;
const isSomeChildElementFocused = useIsElementFocused(rootRef);
const focusedIndex = useFocusedIndex(fieldsLength);
const hasToBeFocused = (index) => isSomeChildElementFocused && focusedIndex === index;

return (
<fieldset
ref={rootRef}
id={id}
data-test-repeatable-field
className={classnames(css.repeatableField, { [css.hasMargin]: hasMargin }, className)}
Expand Down Expand Up @@ -78,7 +83,10 @@ const RepeatableField = ({
key={getFieldUniqueKey(field, index, fields)}
data-test-repeatable-field-list-item
>
<RepeatableFieldContent isFocused={focusedIndex === index} >
<RepeatableFieldContent
rootRef={rootRef}
isFocused={hasToBeFocused(index)}
>
{renderField(field, index, fields)}
</RepeatableFieldContent>
{
Expand Down
7 changes: 3 additions & 4 deletions lib/RepeatableField/RepeatableFieldContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { getFirstFocusable } from "../../util/getFocusableElements";
import css from "./RepeatableField.css";

export const RepeatableFieldContent = ({ children, isFocused }) => {

const callbackRef = useCallback((node) => {
if (node) {
if (node && isFocused) {
const elem = getFirstFocusable(node, true, true);

if (isFocused) {
elem?.focus();
}
elem?.focus();
}
}, [isFocused])

Expand Down
30 changes: 30 additions & 0 deletions lib/RepeatableField/hooks/useIsElementFocused.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useEffect, useState } from "react";

export const useIsElementFocused = (ref) => {
const [isFocused, setIsFocused] = useState(false);

useEffect(() => {
const checkIfFocused = () => {
if (ref.current) {
const focusedElement = document.activeElement;
if (ref.current.contains(focusedElement)) {
setIsFocused(true);
} else {
setIsFocused(false);
}
}
};

window.addEventListener("focusin", checkIfFocused);
window.addEventListener("focusout", checkIfFocused);

checkIfFocused();

return () => {
window.removeEventListener("focusin", checkIfFocused);
window.removeEventListener("focusout", checkIfFocused);
};
}, [ref]);

return isFocused;
};

0 comments on commit ccdf147

Please sign in to comment.