UNPKG

@ui5/webcomponents-react

Version:

React Wrapper for UI5 Web Components and additional components

266 lines (265 loc) 9.15 kB
'use client'; import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; import IconMode from '@ui5/webcomponents/dist/types/IconMode.js'; import InputType from '@ui5/webcomponents/dist/types/InputType.js'; import ListSelectionMode from '@ui5/webcomponents/dist/types/ListSelectionMode.js'; import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js'; import InvisibleMessageMode from '@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js'; import announce from '@ui5/webcomponents-base/dist/util/InvisibleMessage.js'; import iconSearch from '@ui5/webcomponents-icons/dist/search.js'; import { enrichEventWithDetails, useI18nBundle, useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base'; import { clsx } from 'clsx'; import { forwardRef, useEffect, useState } from 'react'; import { FlexBoxAlignItems } from '../../enums/FlexBoxAlignItems.js'; import { CANCEL, CLEAR, SEARCH, SELECT, SELECTED, SELECTED_ITEMS } from '../../i18n/i18n-defaults.js'; import { Button } from '../../webComponents/Button/index.js'; import { Dialog } from '../../webComponents/Dialog/index.js'; import { Icon } from '../../webComponents/Icon/index.js'; import { Input } from '../../webComponents/Input/index.js'; import { List } from '../../webComponents/List/index.js'; import { Text } from '../../webComponents/Text/index.js'; import { Title } from '../../webComponents/Title/index.js'; import { FlexBox } from '../FlexBox/index.js'; import { classNames, styleData } from './SelectDialog.module.css.js'; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; /** * The SelectDialog enables users to filter a comprehensive list via a search field and to select one or more items. */ const SelectDialog = /*#__PURE__*/forwardRef((props, ref) => { const { accessibleName, open, children, className, confirmButtonText, confirmButtonProps, growing, headerText, headerTextAlignCenter, headerTextLevel = TitleLevel.H1, listProps = {}, selectionMode = ListSelectionMode.Single, numberOfSelectedItems, rememberSelections, searchPlaceholder, showClearButton, onClose, onClear, onConfirm, onLoadMore, onSearch, onSearchInput, onSearchReset, onBeforeOpen, onBeforeClose, onOpen, onCancel, ...rest } = props; useStylesheet(styleData, SelectDialog.displayName); const i18nBundle = useI18nBundle('@ui5/webcomponents-react'); const [searchValue, setSearchValue] = useState(''); const [selectedItems, setSelectedItems] = useState([]); const [listComponentRef, listRef] = useSyncRef(listProps.ref); const [internalOpen, setInternalOpen] = useState(open); useEffect(() => { setInternalOpen(open); }, [open]); const handleBeforeOpen = e => { const localSelectedItems = listRef.current?.getSelectedItems() ?? []; if (typeof onBeforeOpen === 'function') { onBeforeOpen(e); } if (selectionMode === ListSelectionMode.Multiple && listRef.current?.hasData) { setSelectedItems(localSelectedItems); } }; const handleAfterOpen = e => { if (typeof onOpen === 'function') { onOpen(e); } listRef.current?.focusFirstItem(); }; const handleSearchInput = e => { if (!e.target.value && e.detail.inputType === '') { handleResetSearch(e); } if (typeof onSearchInput === 'function') { onSearchInput(enrichEventWithDetails(e, { value: e.target.value })); } setSearchValue(e.target.value); }; const handleSearchSubmit = e => { if (typeof onSearch === 'function') { if (e.type === 'keyup' && e.code === 'Enter') { onSearch(enrichEventWithDetails(e, { value: e.target.value })); } if (e.type === 'click') { onSearch(enrichEventWithDetails(e, { value: searchValue })); } } }; const handleResetSearch = e => { if (typeof onSearchReset === 'function') { onSearchReset(enrichEventWithDetails(e, { prevValue: searchValue })); } setSearchValue(''); }; const handleSelectionChange = e => { const { selectedItems } = e.detail; if (typeof listProps?.onSelectionChange === 'function') { listProps.onSelectionChange(e); } if (selectionMode === ListSelectionMode.Multiple) { setSelectedItems(selectedItems); if (selectedItems.length) { announce(i18nBundle.getText(SELECTED_ITEMS, selectedItems.length), InvisibleMessageMode.Polite); } } else { if (typeof onConfirm === 'function') { onConfirm(e); } setInternalOpen(false); } }; const handleClose = e => { setInternalOpen(false); if (typeof onCancel === 'function') { onCancel(e); } }; const handleClear = e => { if (typeof onClear === 'function') { onClear(enrichEventWithDetails(e, { prevSelectedItems: selectedItems })); } setSelectedItems([]); listRef.current?.deselectSelectedItems(); }; const handleConfirm = e => { if (typeof onConfirm === 'function') { onConfirm(enrichEventWithDetails(e, { selectedItems })); } setInternalOpen(false); }; const handleAfterClose = e => { setInternalOpen(false); if (typeof onClose === 'function') { onClose(e); } if (typeof onSearchReset === 'function') { onSearchReset(enrichEventWithDetails(e, { prevValue: searchValue })); } setSearchValue(''); if (!rememberSelections) { listRef.current?.deselectSelectedItems(); } }; const handleBeforeClose = e => { if (typeof onBeforeClose === 'function') { onBeforeClose(e); } if (typeof onCancel === 'function' && e.detail.escPressed) { onCancel(e); } }; return /*#__PURE__*/_jsxs(Dialog, { ...rest, open: internalOpen, "data-component-name": "SelectDialog", ref: ref, className: clsx(classNames.dialog, className), onClose: handleAfterClose, onBeforeOpen: handleBeforeOpen, onOpen: handleAfterOpen, onBeforeClose: handleBeforeClose, accessibleName: accessibleName ?? headerText, children: [/*#__PURE__*/_jsxs("div", { className: classNames.headerContent, slot: "header", "data-sap-ui-fastnavgroup": "true", children: [showClearButton && headerTextAlignCenter && /*#__PURE__*/_jsx(Button, { onClick: handleClear, design: ButtonDesign.Transparent, className: classNames.hiddenClearBtn, tabIndex: -1, "aria-hidden": "true", children: i18nBundle.getText(CLEAR) }), /*#__PURE__*/_jsx(Title, { className: clsx(classNames.title, headerTextAlignCenter && classNames.titleCenterAlign), level: headerTextLevel, children: headerText }), showClearButton && /*#__PURE__*/_jsx(Button, { onClick: handleClear, design: ButtonDesign.Transparent, className: classNames.clearBtn, children: i18nBundle.getText(CLEAR) }), /*#__PURE__*/_jsx(Input, { className: classNames.input, accessibleName: searchPlaceholder ?? i18nBundle.getText(SEARCH), value: searchValue, placeholder: searchPlaceholder ?? i18nBundle.getText(SEARCH), onInput: handleSearchInput, onKeyUp: handleSearchSubmit, type: InputType.Search, showClearIcon: true, icon: /*#__PURE__*/_jsx(_Fragment, { children: /*#__PURE__*/_jsx(Icon, { mode: IconMode.Decorative, name: iconSearch, className: classNames.inputIcon, onClick: handleSearchSubmit, accessibleName: i18nBundle.getText(SEARCH), title: i18nBundle.getText(SEARCH) }) }) })] }), selectionMode === ListSelectionMode.Multiple && (!!selectedItems.length || numberOfSelectedItems > 0) && /*#__PURE__*/_jsx(FlexBox, { alignItems: FlexBoxAlignItems.Center, className: classNames.infoBar, children: /*#__PURE__*/_jsx(Text, { children: `${i18nBundle.getText(SELECTED)}: ${numberOfSelectedItems ?? selectedItems.length}` }) }), /*#__PURE__*/_jsx(List, { ...listProps, ref: listComponentRef, growing: growing, onLoadMore: onLoadMore, selectionMode: selectionMode, onSelectionChange: handleSelectionChange, "data-sap-ui-fastnavgroup": "true", children: children }), /*#__PURE__*/_jsxs("div", { slot: "footer", className: classNames.footer, "data-sap-ui-fastnavgroup": "true", children: [selectionMode === ListSelectionMode.Multiple && /*#__PURE__*/_jsx(Button, { ...confirmButtonProps, onClick: handleConfirm, design: ButtonDesign.Emphasized, children: confirmButtonText ?? i18nBundle.getText(SELECT) }), /*#__PURE__*/_jsx(Button, { onClick: handleClose, design: ButtonDesign.Transparent, children: i18nBundle.getText(CANCEL) })] })] }); }); SelectDialog.displayName = 'SelectDialog'; export { SelectDialog };