@awsui/components-react
Version:
On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en
95 lines • 6.55 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useImperativeHandle, useRef, useState } from 'react';
import clsx from 'clsx';
import { useMergeRefs, useUniqueId } from '@awsui/component-toolkit/internal';
import { InternalButton } from '../button/internal';
import { useInternalI18n } from '../i18n/context';
import { getBaseProps } from '../internal/base-component';
import { matchBreakpointMapping } from '../internal/breakpoints';
import { useContainerBreakpoints } from '../internal/hooks/container-queries';
import { usePrevious } from '../internal/hooks/use-previous';
import InternalLiveRegion from '../live-region/internal';
import InternalSpaceBetween from '../space-between/internal';
import { AdditionalInfo } from './additional-info';
import { gridDefaults } from './grid-defaults';
import { Row } from './row';
import { getGridTemplateColumns } from './utils';
import styles from './styles.css.js';
const InternalAttributeEditor = React.forwardRef(({ additionalInfo, disableAddButton, definition = [{}], gridLayout, items, isItemRemovable = () => true, empty, addButtonText, addButtonVariant, removeButtonText, removeButtonAriaLabel, customRowActions, i18nStrings, onAddButtonClick, onRemoveButtonClick, __internalRootRef, hideAddButton, additionalActions, ...props }, ref) => {
const removeButtonRefs = useRef([]);
const addButtonRef = useRef(null);
const wasNonEmpty = useRef(false);
const [removalAnnouncement, setRemovalAnnouncement] = useState('');
const baseProps = getBaseProps(props);
const isEmpty = items && items.length === 0;
wasNonEmpty.current = wasNonEmpty.current || !isEmpty;
useImperativeHandle(ref, () => ({
focusRemoveButton(rowIndex) {
var _a;
(_a = removeButtonRefs.current[rowIndex]) === null || _a === void 0 ? void 0 : _a.focus();
},
focusAddButton() {
var _a;
(_a = addButtonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
},
}));
const additionalInfoId = useUniqueId('attribute-editor-info');
const infoAriaDescribedBy = additionalInfo ? additionalInfoId : undefined;
const prevItemsLength = usePrevious(items.length);
const i18n = useInternalI18n('attribute-editor');
React.useEffect(() => {
if (prevItemsLength && prevItemsLength > items.length) {
const announcement = i18n('i18nStrings.itemRemovedAriaLive', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.itemRemovedAriaLive);
if (announcement) {
setRemovalAnnouncement(announcement);
}
else {
setRemovalAnnouncement('');
}
}
else {
setRemovalAnnouncement('');
}
// we only want to announce when the number of items decreases (i.e. when an item is removed)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [items, i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.itemRemovedAriaLive]);
if (!gridLayout) {
gridLayout = gridDefaults[definition.length];
if (!gridLayout) {
console.warn('AttributeEditor', '`gridLayout` is required for more than 6 attributes. Cannot render.');
gridLayout = [];
}
}
const gridLayoutBreakpoints = gridLayout.reduce((acc, layout) => ({
...acc,
[layout.breakpoint || 'default']: layout,
}), {});
const [breakpoint, breakpointRef] = useContainerBreakpoints(Object.keys(gridLayoutBreakpoints));
const mergedRef = useMergeRefs(breakpointRef, __internalRootRef);
const gridLayoutForBreakpoint = matchBreakpointMapping(gridLayoutBreakpoints, breakpoint || 'default');
if (!gridLayoutForBreakpoint) {
console.warn('AttributeEditor', `No \`gridLayout\` entry found for breakpoint ${breakpoint}. Cannot render.`);
return React.createElement("div", null);
}
const totalColumnsInLayout = gridLayoutForBreakpoint.rows.reduce((total, columns) => total + columns.length, 0);
if (totalColumnsInLayout !== definition.length) {
console.warn('AttributeEditor', `Incorrect number of columns in layout (${totalColumnsInLayout}) for definition (${definition.length}). Cannot render.`);
return React.createElement("div", null);
}
return (React.createElement("div", { ...baseProps, ref: mergedRef, className: clsx(baseProps.className, styles.root), style: { gridTemplateColumns: getGridTemplateColumns(gridLayoutForBreakpoint) } },
isEmpty && React.createElement("div", { className: clsx(styles.empty, wasNonEmpty.current && styles['empty-appear']) }, empty),
items.map((item, index) => (React.createElement(Row, { key: index, index: index, breakpoint: breakpoint, layout: gridLayoutForBreakpoint, item: item, definition: definition, i18nStrings: i18nStrings, removable: isItemRemovable(item), removeButtonText: removeButtonText, removeButtonRefs: removeButtonRefs.current, customRowActions: customRowActions, onRemoveButtonClick: onRemoveButtonClick, removeButtonAriaLabel: removeButtonAriaLabel }))),
React.createElement("div", { className: styles['add-row'] },
(!hideAddButton || additionalActions) && (React.createElement(InternalSpaceBetween, { size: "xs", direction: "horizontal" },
!hideAddButton && (React.createElement(InternalButton, { className: styles['add-button'], disabled: disableAddButton,
// Using aria-disabled="true" and tabindex="-1" instead of "disabled"
// because focus can be dynamically moved to this button by calling
// `focusAddButton()` on the ref.
nativeButtonAttributes: disableAddButton ? { tabIndex: -1 } : {}, __skipNativeAttributesWarnings: true, __focusable: true, onClick: onAddButtonClick, formAction: "none", ref: addButtonRef, ariaDescribedby: infoAriaDescribedBy, variant: addButtonVariant, iconName: addButtonVariant === 'inline-link' ? 'add-plus' : undefined }, addButtonText)),
additionalActions)),
React.createElement(InternalLiveRegion, { "data-testid": "removal-announcement", tagName: "span", hidden: true, delay: 5, key: items.length }, removalAnnouncement),
!!additionalInfo && React.createElement(AdditionalInfo, { id: infoAriaDescribedBy }, additionalInfo))));
});
export default InternalAttributeEditor;
//# sourceMappingURL=internal.js.map