UNPKG

@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

147 lines • 8.64 kB
import { __rest } from "tslib"; // 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 { useContainerQuery } from '@awsui/component-toolkit'; import { getLogicalBoundingClientRect } from '@awsui/component-toolkit/internal'; import { getAnalyticsMetadataAttribute } from '@awsui/component-toolkit/internal/analytics-metadata'; import { InternalButton } from '../button/internal'; import InternalButtonDropdown from '../button-dropdown/internal'; import { useInternalI18n } from '../i18n/context'; import InternalIcon from '../icon/internal'; import { getBaseProps } from '../internal/base-component'; import { fireCancelableEvent } from '../internal/events'; import { useMergeRefs } from '../internal/hooks/use-merge-refs'; import { checkSafeUrl } from '../internal/utils/check-safe-url'; import { createWidgetizedComponent } from '../internal/widgets'; import { AllItemsDropdown } from './all-items-dropdown'; import { BreadcrumbItem } from './item/item'; import { BreadcrumbGroupSkeleton } from './skeleton'; import { getEventDetail, getItemsDisplayProperties } from './utils'; import analyticsSelectors from './analytics-metadata/styles.css.js'; import styles from './styles.css.js'; /** * Provided for backwards compatibility */ const DEFAULT_EXPAND_ARIA_LABEL = 'Show path'; const getEllipsisDropdownTrigger = ({ ariaLabel, triggerRef, testUtilsClass, isOpen, onClick }) => { return (React.createElement(InternalButton, { ref: triggerRef, className: testUtilsClass, onClick: event => { event.preventDefault(); onClick(); }, ariaExpanded: isOpen, "aria-haspopup": true, ariaLabel: ariaLabel, variant: "breadcrumb-group", formAction: "none" }, "...")); }; const EllipsisDropdown = ({ ariaLabel, dropdownItems, onDropdownItemClick, onDropdownItemFollow, visible, }) => { var _a; const i18n = useInternalI18n('breadcrumb-group'); return (React.createElement("li", { className: clsx(styles.ellipsis, visible && styles.visible) }, React.createElement(InternalButtonDropdown, { ariaLabel: (_a = i18n('expandAriaLabel', ariaLabel)) !== null && _a !== void 0 ? _a : DEFAULT_EXPAND_ARIA_LABEL, items: dropdownItems, onItemClick: onDropdownItemClick, onItemFollow: onDropdownItemFollow, customTriggerBuilder: getEllipsisDropdownTrigger, linkStyle: true, analyticsMetadataTransformer: metadata => { var _a, _b; if ((_a = metadata.detail) === null || _a === void 0 ? void 0 : _a.id) { delete metadata.detail.id; } if ((_b = metadata.detail) === null || _b === void 0 ? void 0 : _b.position) { metadata.detail.position = `${parseInt(metadata.detail.position, 10) + 1}`; } return metadata; } }), React.createElement("span", { className: styles.icon }, React.createElement(InternalIcon, { name: "angle-right" })))); }; const areArrayEqual = (first, second) => { if (first.length !== second.length) { return false; } return first.every((item, index) => item === second[index]); }; export function BreadcrumbGroupImplementation(_a) { var { items = [], ariaLabel, expandAriaLabel, onClick, onFollow, __internalRootRef, __injectAnalyticsComponentMetadata } = _a, props = __rest(_a, ["items", "ariaLabel", "expandAriaLabel", "onClick", "onFollow", "__internalRootRef", "__injectAnalyticsComponentMetadata"]); for (const item of items) { checkSafeUrl('BreadcrumbGroup', item.href); } const baseProps = getBaseProps(props); const [navWidth, navRef] = useContainerQuery(rect => rect.borderBoxWidth); const mergedRef = useMergeRefs(navRef, __internalRootRef); const itemsRefs = useRef({ ghost: {}, real: {} }); const setBreadcrumb = (type, index, node) => { if (node) { itemsRefs.current[type][index] = node; } else { delete itemsRefs.current[type][index]; } }; const [itemsWidths, setItemsWidths] = useState({ ghost: [], real: [] }); useEffect(() => { if (itemsRefs.current) { const newItemsWidths = { ghost: [], real: [] }; for (const node of Object.values(itemsRefs.current.ghost)) { const width = getLogicalBoundingClientRect(node).inlineSize; newItemsWidths.ghost.push(width); } for (const node of Object.values(itemsRefs.current.real)) { const width = getLogicalBoundingClientRect(node).inlineSize; newItemsWidths.real.push(width); } setItemsWidths(oldWidths => { if (!areArrayEqual(newItemsWidths.ghost, oldWidths.ghost) || !areArrayEqual(newItemsWidths.real, oldWidths.real)) { return newItemsWidths; } else { return oldWidths; } }); } }, [items, navWidth]); const { collapsed } = getItemsDisplayProperties(itemsWidths.ghost, navWidth); let breadcrumbItems = items.map((item, index) => { const isLast = index === items.length - 1; const isDisplayed = index === 0 || index > collapsed; const clickAnalyticsMetadata = { action: 'click', detail: { position: `${index + 1}`, label: `.${analyticsSelectors['breadcrumb-item']}`, href: item.href || '', }, }; return (React.createElement("li", Object.assign({ className: clsx(styles.item, !isDisplayed && styles.hide), key: index }, (isLast ? {} : getAnalyticsMetadataAttribute(clickAnalyticsMetadata)), { ref: node => setBreadcrumb('real', `${index}`, node) }), React.createElement(BreadcrumbItem, { item: item, onClick: onClick, onFollow: onFollow, itemIndex: index, totalCount: items.length, isTruncated: itemsWidths.ghost[index] - itemsWidths.real[index] > 0 }))); }); const hiddenBreadcrumbItems = items.map((item, index) => (React.createElement("li", { className: styles['ghost-item'], key: index, ref: node => setBreadcrumb('ghost', `${index}`, node) }, React.createElement(BreadcrumbItem, { item: item, itemIndex: index, totalCount: items.length, isGhost: true })))); const getEventItem = (e) => { const { id } = e.detail; return items[parseInt(id)]; }; // Add ellipsis if (breadcrumbItems.length >= 2) { const dropdownItems = items .slice(1, 1 + collapsed) .map((item, index) => ({ id: (index + 1).toString(), text: item.text, href: item.href || '#', })); breadcrumbItems = [ breadcrumbItems[0], React.createElement(EllipsisDropdown, { key: 'ellipsis', visible: collapsed > 0, ariaLabel: expandAriaLabel, dropdownItems: dropdownItems, onDropdownItemClick: e => fireCancelableEvent(onClick, getEventDetail(getEventItem(e)), e), onDropdownItemFollow: e => fireCancelableEvent(onFollow, getEventDetail(getEventItem(e)), e) }), ...breadcrumbItems.slice(1), ]; } const componentAnalyticsMetadata = { name: 'awsui.BreadcrumbGroup', label: { root: 'self' }, }; return (React.createElement("nav", Object.assign({}, baseProps, { className: clsx(styles['breadcrumb-group'], baseProps.className), "aria-label": ariaLabel || undefined, ref: mergedRef }, (__injectAnalyticsComponentMetadata ? Object.assign({}, getAnalyticsMetadataAttribute({ component: componentAnalyticsMetadata, })) : {})), collapsed > 0 && collapsed === items.length - 1 ? (React.createElement(AllItemsDropdown, { items: items, onItemClick: e => e.detail.id !== (items.length - 1).toString() && fireCancelableEvent(onClick, getEventDetail(getEventItem(e)), e), onItemFollow: e => e.detail.id !== (items.length - 1).toString() && fireCancelableEvent(onFollow, getEventDetail(getEventItem(e)), e) })) : (React.createElement("ol", { className: styles['breadcrumb-group-list'] }, breadcrumbItems)), React.createElement("ol", { className: clsx(styles['breadcrumb-group-list'], styles.ghost), "aria-hidden": true, tabIndex: -1 }, hiddenBreadcrumbItems))); } export const createWidgetizedBreadcrumbGroup = createWidgetizedComponent(BreadcrumbGroupImplementation, BreadcrumbGroupSkeleton); //# sourceMappingURL=implementation.js.map