@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
81 lines • 5.8 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { useSingleTabStopNavigation } from '@awsui/component-toolkit/internal';
import { useInternalI18n } from '../../i18n/context';
import Icon from '../../icon/internal';
import { usePrevious } from '../../internal/hooks/use-previous';
import InternalLiveRegion from '../../live-region/internal';
import { DisabledInlineEditor } from './disabled-inline-editor';
import { InlineEditor } from './inline-editor';
import { TableTdElement } from './td-element';
import styles from './styles.css.js';
const submitHandlerFallback = () => {
throw new Error('The function `handleSubmit` is required for editable columns');
};
function TableCellEditable({ item, column, isEditing, onEditStart, onEditEnd, submitEdit, ariaLabels, successfulEdit = false, ...rest }) {
var _a, _b, _c;
const i18n = useInternalI18n('table');
const editActivateRef = useRef(null);
const tdNativeAttributes = {
'data-inline-editing-active': isEditing.toString(),
};
const isFocusMoveNeededRef = useRef(false);
const isExpandableColumn = rest.level !== undefined;
useEffect(() => {
if (!isEditing && editActivateRef.current && isFocusMoveNeededRef.current) {
isFocusMoveNeededRef.current = false;
editActivateRef.current.focus();
}
}, [isEditing]);
// To improve the initial page render performance we only show the edit icon when necessary.
const [hasFocus, setHasFocus] = useState(false);
const prevSuccessfulEdit = usePrevious(successfulEdit);
const prevHasFocus = usePrevious(hasFocus);
const [showSuccessIcon, setShowSuccessIcon] = useState(false);
useEffect(() => {
// Hide the success icon after a successful edit, when cell loses focus.
if (successfulEdit && prevSuccessfulEdit && !hasFocus && prevHasFocus) {
setShowSuccessIcon(false);
}
// Show success icon right after a successful edit, when `successfulEdit` switches to true.
if (successfulEdit && !prevSuccessfulEdit) {
setShowSuccessIcon(true);
}
}, [hasFocus, successfulEdit, prevHasFocus, prevSuccessfulEdit]);
const { tabIndex: editActivateTabIndex } = useSingleTabStopNavigation(editActivateRef);
return (React.createElement(TableTdElement, { ...rest, nativeAttributes: tdNativeAttributes, isEditing: isEditing, hasSuccessIcon: showSuccessIcon && hasFocus, onClick: !isEditing && !isExpandableColumn ? onEditStart : undefined, onFocus: () => setHasFocus(true), onBlur: () => setHasFocus(false) }, isEditing && column.editConfig ? (React.createElement(InlineEditor, { ariaLabels: ariaLabels, column: column, item: item, onEditEnd: options => {
setShowSuccessIcon(false);
isFocusMoveNeededRef.current = options.refocusCell;
onEditEnd(options.cancelled);
}, submitEdit: submitEdit !== null && submitEdit !== void 0 ? submitEdit : submitHandlerFallback })) : (React.createElement(React.Fragment, null,
column.cell(item),
showSuccessIcon && hasFocus && (React.createElement(React.Fragment, null,
React.createElement("span", { className: styles['body-cell-success'], onMouseDown: e => {
// Prevent the editor's Button blur event to be fired when clicking the success icon.
// This prevents unfocusing the button and triggers the `TableTdElement` onClick event which initiates the edit mode.
e.preventDefault();
} },
React.createElement(Icon, { name: "status-positive", variant: "success", ariaLabel: (_a = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.successfulEditLabel) === null || _a === void 0 ? void 0 : _a.call(ariaLabels, column) })),
React.createElement(InternalLiveRegion, { tagName: "span", hidden: true }, i18n('ariaLabels.successfulEditLabel', (_b = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.successfulEditLabel) === null || _b === void 0 ? void 0 : _b.call(ariaLabels, column))))),
React.createElement("div", { className: styles['body-cell-editor-wrapper'] },
React.createElement("button", { className: clsx(styles['body-cell-editor'], isExpandableColumn && styles['body-cell-editor-focusable']), "aria-label": (_c = ariaLabels === null || ariaLabels === void 0 ? void 0 : ariaLabels.activateEditLabel) === null || _c === void 0 ? void 0 : _c.call(ariaLabels, column, item), ref: editActivateRef, onClick: !isEditing && isExpandableColumn ? onEditStart : undefined, tabIndex: editActivateTabIndex },
React.createElement("span", { className: styles['body-cell-editor-icon'] },
React.createElement(Icon, { name: "edit" }))))))));
}
export function TableBodyCell(props) {
var _a, _b;
const editDisabledReason = (_b = (_a = props.column.editConfig) === null || _a === void 0 ? void 0 : _a.disabledReason) === null || _b === void 0 ? void 0 : _b.call(_a, props.item);
// Inline editing is deactivated for expandable column because editable cells are interactive
// and cannot include interactive content such as expand toggles.
if (editDisabledReason) {
return React.createElement(DisabledInlineEditor, { editDisabledReason: editDisabledReason, ...props });
}
if (props.isEditable || props.isEditing) {
return React.createElement(TableCellEditable, { ...props });
}
const { column, item } = props;
return (React.createElement(TableTdElement, { ...props, isEditable: false }, column.cell(item)));
}
//# sourceMappingURL=index.js.map