@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
122 lines • 8.8 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useEffect, useImperativeHandle, useRef, useState } from 'react';
import clsx from 'clsx';
import { useMergeRefs } from '@awsui/component-toolkit/internal';
import { getAnalyticsMetadataAttribute } from '@awsui/component-toolkit/internal/analytics-metadata';
import { InternalButton } from '../button/internal';
import { useInternalI18n } from '../i18n/context';
import InternalIcon from '../icon/internal';
import { DATA_ATTR_ANALYTICS_ALERT } from '../internal/analytics/selectors';
import { getBaseProps } from '../internal/base-component';
import VisualContext from '../internal/components/visual-context';
import { LinkDefaultVariantContext } from '../internal/context/link-default-variant-context';
import { fireNonCancelableEvent } from '../internal/events';
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
import { persistAlertDismiss, retrieveAlertDismiss } from '../internal/persistence';
import { awsuiPluginsInternal } from '../internal/plugins/api';
import { createUseDiscoveredAction, createUseDiscoveredContent } from '../internal/plugins/helpers';
import useContainerWidth from '../internal/utils/use-container-width';
import { ActionsWrapper } from './actions-wrapper';
import { getAlertStyles, getDismissButtonStyles, getIconStyles } from './style';
import analyticsSelectors from './analytics-metadata/styles.css.js';
import styles from './styles.css.js';
const typeToIcon = {
error: 'status-negative',
warning: 'status-warning',
success: 'status-positive',
info: 'status-info',
};
const useDiscoveredAction = createUseDiscoveredAction(awsuiPluginsInternal.alert.onActionRegistered);
const useDiscoveredContent = createUseDiscoveredContent('alert', awsuiPluginsInternal.alertContent);
const InternalAlert = React.forwardRef(({ type, i18nStrings, visible = true, dismissible, children, header, buttonText, action, onDismiss, onButtonClick, __internalRootRef, statusIconAriaLabel: deprecatedStatusIconAriaLabel, dismissAriaLabel: deprecatedDismissAriaLabel, messageSlotId, style, persistenceConfig, ...rest }, ref) => {
var _a, _b;
const baseProps = getBaseProps(rest);
const i18n = useInternalI18n('alert');
const focusRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => {
if (focusRef.current) {
focusRef.current.tabIndex = -1;
focusRef.current.focus();
}
},
}));
const handleBlur = () => {
if (focusRef.current) {
focusRef.current.removeAttribute('tabindex');
}
};
const { discoveredActions, headerRef: headerRefAction, contentRef: contentRefAction } = useDiscoveredAction(type);
const { initialHidden, headerReplacementType, contentReplacementType, headerRef: headerRefContent, contentRef: contentRefContent, replacementHeaderRef, replacementContentRef, } = useDiscoveredContent({ type, header, children });
const [containerWidth, containerMeasureRef] = useContainerWidth();
const containerRef = useMergeRefs(containerMeasureRef, __internalRootRef);
const headerRef = useMergeRefs(headerRefAction, headerRefContent);
const contentRef = useMergeRefs(contentRefAction, contentRefContent);
const [isPersistentlyDismissed, setIsPersistentlyDismissed] = useState(!!(persistenceConfig && persistenceConfig.uniqueKey));
const isRefresh = useVisualRefresh();
const size = isRefresh
? 'normal'
: headerReplacementType !== 'remove' && header && contentReplacementType !== 'remove' && children
? 'big'
: 'normal';
const hasAction = Boolean(action || buttonText || discoveredActions.length);
const analyticsAttributes = {
[DATA_ATTR_ANALYTICS_ALERT]: type,
};
const statusIconAriaLabel = i18n(`i18nStrings.${type}IconAriaLabel`, (_a = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings[`${type}IconAriaLabel`]) !== null && _a !== void 0 ? _a : deprecatedStatusIconAriaLabel);
const dismissAriaLabel = i18n('i18nStrings.dismissAriaLabel', (_b = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.dismissAriaLabel) !== null && _b !== void 0 ? _b : i18n('dismissAriaLabel', deprecatedDismissAriaLabel));
useEffect(() => {
let isMounted = true;
if (persistenceConfig === null || persistenceConfig === void 0 ? void 0 : persistenceConfig.uniqueKey) {
retrieveAlertDismiss(persistenceConfig)
.then(dismissed => {
if (isMounted) {
setIsPersistentlyDismissed(!!dismissed);
}
})
.catch(() => {
if (isMounted) {
setIsPersistentlyDismissed(false);
}
});
}
return () => {
isMounted = false;
};
// Only track specific properties to avoid re-running when persistenceConfig object reference changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [persistenceConfig === null || persistenceConfig === void 0 ? void 0 : persistenceConfig.uniqueKey, persistenceConfig === null || persistenceConfig === void 0 ? void 0 : persistenceConfig.crossServicePersistence]);
const dismiss = () => {
fireNonCancelableEvent(onDismiss);
if (persistenceConfig === null || persistenceConfig === void 0 ? void 0 : persistenceConfig.uniqueKey) {
persistAlertDismiss(persistenceConfig);
}
};
if (isPersistentlyDismissed) {
return null;
}
return (React.createElement("div", { ...baseProps, ...analyticsAttributes, "aria-hidden": !visible, className: clsx(styles.root, { [styles.hidden]: !visible, [styles['initial-hidden']]: initialHidden }, baseProps.className), ref: containerRef },
React.createElement(LinkDefaultVariantContext.Provider, { value: { defaultVariant: 'primary' } },
React.createElement(VisualContext, { contextName: "alert" },
React.createElement("div", { className: clsx(styles.alert, styles[`type-${type}`], styles[`icon-size-${size}`], hasAction && styles['with-action'], dismissible && styles['with-dismiss']), style: getAlertStyles(style) },
React.createElement("div", { className: styles['alert-wrapper'] },
React.createElement("div", { className: styles['alert-focus-wrapper'], ref: focusRef, role: "group", onBlur: handleBlur },
React.createElement("div", { className: clsx(styles.icon, styles.text), style: getIconStyles(style) },
React.createElement(InternalIcon, { name: typeToIcon[type], size: size, ariaLabel: statusIconAriaLabel })),
React.createElement("div", { className: clsx(styles.message, styles.text), id: messageSlotId },
React.createElement("div", { className: clsx(header && styles.header, headerReplacementType !== 'original' ? styles.hidden : analyticsSelectors.header), ref: headerRef }, header),
React.createElement("div", { className: clsx(styles['header-replacement'], headerReplacementType !== 'replaced' ? styles.hidden : analyticsSelectors.header), ref: replacementHeaderRef }),
React.createElement("div", { className: clsx(styles.content, contentReplacementType !== 'original' && styles.hidden), ref: contentRef }, children),
React.createElement("div", { className: clsx(styles['content-replacement'], contentReplacementType !== 'replaced' && styles.hidden), ref: replacementContentRef }))),
React.createElement(ActionsWrapper, { className: styles.action, testUtilClasses: {
actionSlot: styles['action-slot'],
actionButton: styles['action-button'],
}, action: action, discoveredActions: discoveredActions, buttonText: buttonText, onButtonClick: () => fireNonCancelableEvent(onButtonClick), containerWidth: containerWidth, wrappedClass: styles['action-wrapped'] })),
dismissible && (React.createElement("div", { className: styles.dismiss, ...getAnalyticsMetadataAttribute({
action: 'dismiss',
}) },
React.createElement(InternalButton, { className: styles['dismiss-button'], variant: "icon", iconName: "close", formAction: "none", ariaLabel: dismissAriaLabel, onClick: dismiss, style: getDismissButtonStyles(style) }))))))));
});
export default InternalAlert;
//# sourceMappingURL=internal.js.map