@geneui/components
Version:
The Gene UI components library designed for BI tools
503 lines (497 loc) • 18.1 kB
JavaScript
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 };