UNPKG

@geneui/components

Version:

The Gene UI components library designed for BI tools

503 lines (497 loc) 18.1 kB
import { _ as _extends } from '../_rollupPluginBabelHelpers-e8fb2e5c.js'; import React__default, { useState, useCallback, useEffect, useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; import { c as classnames } from '../index-031ff73c.js'; import { o as oneIsRequired, s as stopEvent, n as noop } from '../index-a0e4e333.js'; import '../configs-00612ce0.js'; import useBodyScroll from '../hooks/useBodyScroll.js'; import Button from '../Button/index.js'; import MobilePopUp from '../MobilePopup/index.js'; import '../dateValidation-67caec66.js'; import 'react-dom'; import useClickOutside from '../hooks/useClickOutside.js'; import Popover from '../Popover/index.js'; import Menu from '../Menu/index.js'; import SkeletonLoader from '../SkeletonLoader/index.js'; import KeyValue from '../KeyValue/index.js'; import { s as styleInject } from '../style-inject.es-746bb8ed.js'; import { g as guid } from '../guid-8ddf77b3.js'; import '../tslib.es6-f211516f.js'; import '../Icon/index.js'; import '../Portal/index.js'; import '../GeneUIProvider/index.js'; import '../_commonjsHelpers-24198af3.js'; import '../index-122432cd.js'; import '../hooks/useDeviceType.js'; import '../hooks/useWindowSize.js'; import '../hooks/useDebounce.js'; import '../hooks/useUpdatableRef.js'; import '../hooks/useForceUpdate.js'; import '../Scrollbar/index.js'; import '../Option/index.js'; import '../useEllipsisDetection-4d997d5d.js'; import '../index-6d7e99cd.js'; function CardMenu(_ref) { let { menuOptions = [] } = _ref; const bodyScroll = useBodyScroll(); const [isOpened, setIsOpened] = useState(false); const handleOpen = useCallback(() => { setIsOpened(true); bodyScroll.lock(); }, []); useEffect(() => () => bodyScroll.unlock(), []); const handleClose = useCallback(() => { setIsOpened(false); bodyScroll.unlock(); }, []); const handleOutsideClick = useClickOutside(handleClose); const handleItemClick = useCallback(_ref2 => { let { onClick, disabled, ...item } = _ref2; if (!disabled) { onClick && onClick(event); handleClose(item); } }, [handleClose]); const options = useMemo(() => menuOptions.filter(Boolean).map(item => { if ( /*#__PURE__*/React__default.isValidElement(item)) { return { component: /*#__PURE__*/React__default.cloneElement(item, { onClick: () => handleItemClick(item.props) }) }; } return { ...item, onClick: () => handleItemClick(item) }; }), [menuOptions, handleItemClick]); return /*#__PURE__*/React__default.createElement(Popover, { swipeable: true, screenType: "mobile", isOpen: isOpened, onSwipedDown: handleClose, contentRef: handleOutsideClick, Content: /*#__PURE__*/React__default.createElement(Menu, { screenType: "mobile", data: [...options, { title: 'Cancel', onClick: handleClose, icon: 'bc-icon-clear', border: 'top' }] }) }, /*#__PURE__*/React__default.createElement(Button, { onClick: handleOpen, icon: "bc-icon-more-horizontal", appearance: "minimal", withShadow: true })); } var css_248z = "[data-gene-ui-version=\"2.16.5\"] .card-holder{position:relative;width:100%}[data-gene-ui-version=\"2.16.5\"] .card-holder.with-button{padding-inline-end:1.2rem}[data-gene-ui-version=\"2.16.5\"] .card-holder+.card-holder{padding-top:1rem}[data-gene-ui-version=\"2.16.5\"] .ReactVirtualized__Grid .card-holder{left:0;position:absolute;width:100%}[data-gene-ui-version=\"2.16.5\"] .card-container{position:relative;width:100%}[data-gene-ui-version=\"2.16.5\"] .card-more-button-holder{background:var(--background);border-radius:100%;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:1}html[dir=rtl] .card-more-button-holder{transform:translate(50%,-50%)}html:not([dir=rtl]) .card-more-button-holder{left:100%}html[dir=rtl] .card-more-button-holder{right:100%}[data-gene-ui-version=\"2.16.5\"] .card-c-holder{grid-column-gap:1rem;grid-row-gap:1.2rem;background:var(--background);border-radius:1rem;display:grid;font:600 1.6rem/2.2rem var(--font-family);grid-template-columns:1fr 1fr;padding:1.4rem 1rem;position:relative;width:100%}[data-gene-ui-version=\"2.16.5\"] .card-c-holder.border:after{border:1px solid var(--background-sc);border-radius:inherit;content:\"\";display:block;height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%}[data-gene-ui-version=\"2.16.5\"] .card-c-holder.shadow{box-shadow:0 1px .3rem 0 #0000001a}[data-gene-ui-version=\"2.16.5\"] .card-c-holder .card-list-col{overflow:hidden}[data-gene-ui-version=\"2.16.5\"] .card-c-holder .card-list-col .kv-label{font:600 1.2rem/1.6rem var(--font-family);margin:0 0 .4rem;opacity:.5}[data-gene-ui-version=\"2.16.5\"] .card-c-holder a{color:var(--hero)}[data-gene-ui-version=\"2.16.5\"] .expand-card-holder{background:var(--background);bottom:0;padding:0 0 1.6rem;position:-webkit-sticky;position:sticky;width:100%;z-index:10}"; styleInject(css_248z); function Col(_ref) { let { col, row, index, ...restProps } = _ref; const guidRef = useRef(null); const mounted = useRef(null); const { getter, formatter, colRenderer, dataKey, text } = col; const getterValue = getter ? getter(row, index) : row.data[dataKey]; const formattedValue = formatter ? formatter(getterValue, row, index) : getterValue; const isValuePromise = formattedValue instanceof Promise; const [promiseValue, setPromiseValue] = useState(() => { if (isValuePromise) { guidRef.current = guid(); return guidRef.current; } }); useEffect(() => { mounted.current = true; isValuePromise && formattedValue.then(result => mounted.current && setPromiseValue(result)); return () => { mounted.current = false; }; }, [formattedValue, isValuePromise, mounted.current]); const value = isValuePromise ? promiseValue : formattedValue; const colNode = colRenderer ? colRenderer(value, index, row) : value; return /*#__PURE__*/React__default.createElement(KeyValue, _extends({}, restProps, { key: dataKey, label: text, appearance: "vertical", value: /*#__PURE__*/React__default.createElement(SkeletonLoader, { height: 20, isBusy: guidRef.current && promiseValue === guidRef.current }, colNode || null), className: "card-list-col" })); } Col.propTypes = { /** * sortFn: Custom sort function for columns.((prev: PropTypes.rows[item], next: PropTypes.rows[item], rows: PropTypes.rows, dataKey: string) => { * if (prev is less than next by some ordering criterion) { * return -1; * } * if (prev is greater than next by the ordering criterion) { * return 1; * } * prev is equal to next * return 0; * } * }) * * text: Text value for columns * * render: Function to render custom text.((column: PropTypes.columns[item], index: number, isEditActive: boolean) => return any) * * current column's data key * * colRenderer: Render custom component on certain column of each row. ((value: string || number, index: number, row: PropTypes.rows[item], isEditActive: boolean) => { * return <div>Hello World</div>}) * * getter: Function to define custom text. ((row: PropTypes.rows[item], index: number, isEditActive: boolean)) => { * return some string * }) * * formatter: Function tp format displaying text. ((middleText: string, row: PropTypes.rows[item], index: number, isEditActive: boolean) => { * return some string * }) * */ col: PropTypes.shape({ sortFn: PropTypes.func, ...oneIsRequired({ text: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), render: PropTypes.func }), dataKey: PropTypes.string, colRenderer: PropTypes.func, getter: PropTypes.func, formatter: PropTypes.func }).isRequired, /** * data: rows column's data * className: additional className for row element * render: Render custom component on (row: PropTypes.rows[item] index: number) => { * return <div>Hello World</div>}) */ row: PropTypes.shape({ data: PropTypes.object, className: PropTypes.string, render: PropTypes.func }), /** * Index of row */ index: PropTypes.number }; var Col$1 = /*#__PURE__*/React__default.memo(Col); function Card(_ref) { let { renderRowNestedChildren, isCustomScrollElement, viewCardText, expandText, cancelText, expandedCloseText, hideMore, expandedText, rowActionBar, columnLimit, columnKey, getPopupProps, virtualizedList, isEditMode, rowHeightCache, expandDisabled, rowExtraClick, rowExtraClickNeeded, rowExtraClickMenuTitle, getExpandIconDisableState, onRowClick, className, columns, shadow, border, index, row, closeWithOutsideClick, ...restProps } = _ref; const bodyScroll = useBodyScroll(); const nestedElementPopupRef = useRef(null); const [openDetailed, setOpenDetailed] = useState(false); const [expanded, setExpanded] = useState(false); const goToDetailed = useCallback(() => setOpenDetailed(true), []); const handleExpand = useCallback(() => setExpanded(true), []); const handleCardClick = useCallback(e => onRowClick(e, index), [index, onRowClick]); const menuOptions = rowActionBar(row, index) || []; const propsForPopup = getPopupProps(row, index) || {}; const customNestedElement = renderRowNestedChildren && renderRowNestedChildren(row, index, nestedElementPopupRef); const extraClickNeeded = typeof rowExtraClickNeeded === 'function' ? rowExtraClickNeeded(row, index) : rowExtraClickNeeded; const onExtraClick = useCallback(e => { stopEvent(e); extraClickNeeded && rowExtraClick && rowExtraClick(e, row.data, index, row); }, [index, row, rowExtraClick, extraClickNeeded]); const isExpandIconDisabled = useMemo(() => getExpandIconDisableState ? getExpandIconDisableState(row, index) : expandDisabled, [getExpandIconDisableState, expandDisabled, index, row]); useEffect(() => { if (virtualizedList) { rowHeightCache.clear(index); virtualizedList.recomputeRowHeights(index); } }, [virtualizedList, columns.length, isEditMode]); useEffect(() => { openDetailed || isCustomScrollElement && !expanded ? bodyScroll.lock() : bodyScroll.unlock(); return () => bodyScroll.unlock(); }, [openDetailed, isCustomScrollElement, expanded]); const handleCloseDetails = useCallback((_, isBackdrop) => { isBackdrop ? closeWithOutsideClick && setOpenDetailed(false) : setOpenDetailed(false); }, [closeWithOutsideClick]); const handleCloseExpand = useCallback((_, isBackdrop) => { isBackdrop ? closeWithOutsideClick && setExpanded(false) : setExpanded(false); }, [closeWithOutsideClick]); return /*#__PURE__*/React__default.createElement("div", _extends({ className: classnames('card-holder with-button', className), onClick: handleCardClick }, restProps), /*#__PURE__*/React__default.createElement("div", { className: "card-container" }, !hideMore && /*#__PURE__*/React__default.createElement("div", { className: "card-more-button-holder" }, /*#__PURE__*/React__default.createElement(CardMenu, { menuOptions: [{ title: viewCardText, onClick: goToDetailed, icon: 'bc-icon-report', color: 'hero', border: menuOptions && !customNestedElement ? 'bottom' : 'none' }, customNestedElement && { title: expandText, disabled: isExpandIconDisabled, onClick: handleExpand, icon: 'bc-icon-expand', color: 'hero', border: menuOptions.length && !extraClickNeeded ? 'bottom' : 'none' }, extraClickNeeded && { title: rowExtraClickMenuTitle, onClick: onExtraClick, icon: 'bc-icon-expand', color: 'hero', border: menuOptions.length ? 'bottom' : 'none' }, ...menuOptions] })), /*#__PURE__*/React__default.createElement("div", { className: classnames('card-c-holder', { shadow, border }) }, columns.slice(0, columnLimit).map(col => /*#__PURE__*/React__default.createElement(Col$1, { key: col[columnKey], col: col, index: index, row: row })))), /*#__PURE__*/React__default.createElement(MobilePopUp, _extends({ isOpened: openDetailed, leftActionClick: handleCloseDetails, onBackdropClick: handleCloseDetails }, propsForPopup), /*#__PURE__*/React__default.createElement("div", { className: "quick-view-holder" }, columns.map(col => /*#__PURE__*/React__default.createElement(Col$1, { key: col[columnKey], col: col, index: index, row: row }))), customNestedElement && /*#__PURE__*/React__default.createElement("div", { className: "expand-card-holder" }, /*#__PURE__*/React__default.createElement(Button, { icon: "bc-icon-expand", flexibility: "full-width", onClick: () => setExpanded(true), disabled: isExpandIconDisabled }, expandText))), customNestedElement && /*#__PURE__*/React__default.createElement(MobilePopUp, { isOpened: expanded, title: expandedText, ref: nestedElementPopupRef, leftAction: { text: expandedCloseText }, onBackdropClick: handleCloseExpand, leftActionClick: handleCloseExpand }, customNestedElement(row, index, nestedElementPopupRef))); } Card.propTypes = { /** * Close card details and expanded popups with outside click */ closeWithOutsideClick: PropTypes.bool, /** * Has component shadow or no */ shadow: PropTypes.bool, /** * Has component border or no */ border: PropTypes.bool, /** * Index of row */ index: PropTypes.number, /** * Additional classname */ className: PropTypes.string, /** * data: rows column's data * className: additional className for row element * render: Render custom component on (row: PropTypes.rows[item] index: number) => { * return <div>Hello World</div>}) */ row: PropTypes.shape({ data: PropTypes.object, className: PropTypes.string, render: PropTypes.func }), /** * sortFn: Custom sort function for columns.((prev: PropTypes.rows[item], next: PropTypes.rows[item], rows: PropTypes.rows, dataKey: string) => { * if (prev is less than next by some ordering criterion) { * return -1; * } * if (prev is greater than next by the ordering criterion) { * return 1; * } * prev is equal to next * return 0; * } * }) * * text: Text value for columns * * render: Function to render custom text.((column: PropTypes.columns[item], index: number, isEditActive: boolean) => return any) * * sortable: Allows sorting if true * * resizable: Allows resizing if true * * current column's data key * * draggable: Allows dragging if true * * colRenderer: Render custom component on certain column of each row. ((value: string || number, index: number, row: PropTypes.rows[item], isEditActive: boolean) => { * return <div>Hello World</div>}) * * getter: Function to define custom text. ((row: PropTypes.rows[item], index: number, isEditActive: boolean)) => { * return some string * }) * * formatter: Function tp format displaying text. ((middleText: string, row: PropTypes.rows[item], index: number, isEditActive: boolean) => { * return some string * }) * */ columns: PropTypes.arrayOf(PropTypes.shape({ sortFn: PropTypes.func, ...oneIsRequired({ text: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), render: PropTypes.func }), sortable: PropTypes.bool, resizable: PropTypes.bool, dataKey: PropTypes.string, draggable: PropTypes.bool, colRenderer: PropTypes.func, getter: PropTypes.func, formatter: PropTypes.func, hide: PropTypes.bool })).isRequired, /** * Number of columns that will be shown */ columnLimit: PropTypes.number, /** * Function which will return Array of objects as row's action bar on the right corner of the row. ((row: PropTypes.rows[item] ,index: number) => []) */ rowActionBar: PropTypes.func, /** * Function which will return props for mobile popup. ((row: PropTypes.rows[item] ,index: number) => {}) */ getPopupProps: PropTypes.func, /** * Fires event when clicked on row * (event: SyntheticEvent, index: number) => void */ onRowClick: PropTypes.func, /** * Text for View Card */ viewCardText: PropTypes.string, /** * Text for Expand */ expandText: PropTypes.string, /** * Text for Cancel */ cancelText: PropTypes.string, /** * Text for Expanded popup close button */ expandedCloseText: PropTypes.string, /** * Text for Expanded popup title */ expandedText: PropTypes.string, /** * Function which should return null or another * Function which will return valid node */ renderRowNestedChildren: PropTypes.func, /** * Extra click function for rows. ((e: event object, data: object, index: number, row: PropTypes.rows[item]) => custom logic) */ rowExtraClick: PropTypes.func, /** * Expand button disabled state */ expandDisabled: PropTypes.bool, /** * Is card in edit mode */ isEditMode: PropTypes.bool, /** * Hide show more button */ hideMore: PropTypes.bool, /** * Function for determining which rows should have extra click. ((e: event object, data: object, index: number, row: PropTypes.rows[item]) => return true or false) */ rowExtraClickNeeded: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), /** * Title for rowExtraClick menu item */ rowExtraClickMenuTitle: PropTypes.string }; Card.defaultProps = { rowActionBar: noop, getPopupProps: noop, onRowClick: noop, rowExtraClickNeeded: noop, viewCardText: 'View Card', expandText: 'Expand', cancelText: 'Cancel', expandedText: 'Expanded', expandedCloseText: 'Close' }; var Card$1 = /*#__PURE__*/React__default.memo(Card); export { Card$1 as default };