@atlaskit/form
Version:
A form allows people to input information.
82 lines (81 loc) • 3.19 kB
JavaScript
import React, { Children, isValidElement, useContext, useMemo, useState } from 'react';
import ExitingPersistence from '@atlaskit/motion/exiting-persistence';
import { fg } from '@atlaskit/platform-feature-flags/fg';
import { FormSubmitContext } from './form-submit-context';
import { MessageWrapperContext } from './message-context';
import MessageGroup from './message-group';
import messageMotion from './message-motion-capability';
/**
* __Message wrapper __
*
* A message wrapper is used to allow assistive technologies, like screen readers, to announce error or
* valid messages. This must be loaded into the DOM before the
* ErrorMessage, ValidMessage is loaded. Otherwise, assistive technologies
* may not render the message.
*
*/
export const MessageWrapper = ({
children
}) => {
const contextValue = {
isWrapper: true,
hasMotionBoundary: false,
transition: 'row'
};
const shouldProvideMotionBoundary = fg('platform-dst-motion-uplift-input') && Children.toArray(children).every(messageMotion.isCapable);
return /*#__PURE__*/React.createElement(MessageWrapperContext.Provider, {
value: contextValue
}, /*#__PURE__*/React.createElement("div", {
"aria-live": "polite",
"data-testid": "message-wrapper"
}, shouldProvideMotionBoundary ? /*#__PURE__*/React.createElement(MotionMessages, null, children) : children));
};
const getChildKeys = children => Children.toArray(children).filter(isValidElement).map(child => child.key).filter(key => key !== null);
const getTransition = (previousKeys, currentKeys) => {
const previous = new Set(previousKeys);
const current = new Set(currentKeys);
const removedCount = previousKeys.filter(key => !current.has(key)).length;
const addedCount = currentKeys.filter(key => !previous.has(key)).length;
if (removedCount > 0 && addedCount > 0) {
return 'instant';
}
if (previousKeys.length === 0 && addedCount > 1) {
return 'groupEnter';
}
if (currentKeys.length === 0 && removedCount > 1) {
return 'groupExit';
}
return 'row';
};
const MotionMessages = ({
children
}) => {
const currentKeys = getChildKeys(children);
const submitCount = useContext(FormSubmitContext);
const [transition, setTransition] = useState(() => ({
keys: currentKeys,
mode: 'row',
submitCount
}));
const hasKeyChange = currentKeys.length !== transition.keys.length || currentKeys.some((key, index) => key !== transition.keys[index]);
const isSubmitUpdate = submitCount !== transition.submitCount;
if (hasKeyChange || isSubmitUpdate) {
setTransition({
keys: currentKeys,
mode: !hasKeyChange ? transition.mode : isSubmitUpdate ? 'instant' : getTransition(transition.keys, currentKeys),
submitCount
});
}
const motionContextValue = useMemo(() => ({
isWrapper: true,
hasMotionBoundary: true,
transition: transition.mode
}), [transition.mode]);
return /*#__PURE__*/React.createElement(MessageWrapperContext.Provider, {
value: motionContextValue
}, /*#__PURE__*/React.createElement(MessageGroup, {
transition: transition.mode
}, /*#__PURE__*/React.createElement(ExitingPersistence, {
appear: true
}, children)));
};