hrm_ui_lib 3.1.11 → 3.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/styles.css +1 -1
- package/components/Modal/Modal.d.ts +1 -6
- package/components/Modal/Modal.js +17 -47
- package/components/Modal/ModalConfirmation.d.ts +1 -1
- package/components/Modal/ModalConfirmation.js +13 -26
- package/components/Select/MultiSelect/MultiBase/MultiBase.js +24 -12
- package/components/Select/MultiSelect/MultiSelect.js +1 -1
- package/components/Select/types.d.ts +1 -0
- package/hooks/useAnimation.d.ts +12 -0
- package/hooks/useAnimation.js +33 -0
- package/hooks/useEscapeKey.d.ts +5 -0
- package/hooks/useEscapeKey.js +16 -0
- package/package.json +1 -1
|
@@ -1,8 +1,3 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { TModalPropTypes } from './types';
|
|
3
|
-
export declare const
|
|
4
|
-
[key: string]: {
|
|
5
|
-
[key: string]: string | number;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
export declare const Modal: (props: TModalPropTypes) => ReactElement;
|
|
3
|
+
export declare const Modal: ({ isOpen, onClose, className, size, closeOnOutsideClick, isMobileFullScreen, ...rest }: TModalPropTypes) => ReactElement | null;
|
|
@@ -12,59 +12,29 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
import { useId, useState } from 'react';
|
|
14
14
|
import classnames from 'classnames';
|
|
15
|
-
import { motion } from 'motion/react';
|
|
16
|
-
import { AnimatePresenceWrapper } from '../../helperComponents/AnimatePresenceWrapper';
|
|
17
15
|
import { useHideBodyScroll, useOnOutsideClick } from '../../hooks';
|
|
16
|
+
import { useAnimation } from '../../hooks/useAnimation';
|
|
18
17
|
import { ModalContent } from './ModalContent';
|
|
19
18
|
import { useIsMobile } from '../../hooks/useGetIsMobile';
|
|
20
19
|
import classNames from 'classnames';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
exit: {
|
|
25
|
-
opacity: 0,
|
|
26
|
-
scale: 0.7,
|
|
27
|
-
transition: {
|
|
28
|
-
duration: 0.2
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
transition: {
|
|
32
|
-
duration: 0.4,
|
|
33
|
-
type: 'spring',
|
|
34
|
-
damping: 55,
|
|
35
|
-
stiffness: 700
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
export const MOBILE_ANIMATION = (isFullScreen) => {
|
|
39
|
-
return {
|
|
40
|
-
initial: {
|
|
41
|
-
height: 0,
|
|
42
|
-
bottom: 0
|
|
43
|
-
},
|
|
44
|
-
animate: {
|
|
45
|
-
height: isFullScreen ? '100%' : 'auto',
|
|
46
|
-
bottom: 0
|
|
47
|
-
},
|
|
48
|
-
exit: {
|
|
49
|
-
height: 0,
|
|
50
|
-
bottom: 0
|
|
51
|
-
},
|
|
52
|
-
transition: {
|
|
53
|
-
duration: 0.3
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
export const Modal = (props) => {
|
|
58
|
-
const { isOpen, onClose, className = '', size = 'medium', closeOnOutsideClick = true, isMobileFullScreen } = props, rest = __rest(props, ["isOpen", "onClose", "className", "size", "closeOnOutsideClick", "isMobileFullScreen"]);
|
|
20
|
+
import { useEscapeKey } from '../../hooks/useEscapeKey';
|
|
21
|
+
export const Modal = (_a) => {
|
|
22
|
+
var { isOpen, onClose, className = '', size = 'medium', closeOnOutsideClick = true, isMobileFullScreen } = _a, rest = __rest(_a, ["isOpen", "onClose", "className", "size", "closeOnOutsideClick", "isMobileFullScreen"]);
|
|
59
23
|
const isMobile = useIsMobile();
|
|
24
|
+
const { animationState, shouldRender } = useAnimation({
|
|
25
|
+
isOpen,
|
|
26
|
+
enterDuration: isMobile ? 0 : 400,
|
|
27
|
+
exitDuration: 200
|
|
28
|
+
});
|
|
60
29
|
const [containerRef, setContainerRef] = useState(null);
|
|
61
30
|
useOnOutsideClick(containerRef, onClose, closeOnOutsideClick && isOpen, useId());
|
|
62
31
|
useHideBodyScroll(isOpen);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
32
|
+
useEscapeKey(onClose, { enabled: isOpen });
|
|
33
|
+
if (!shouldRender) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return (_jsx("div", { className: classnames('modal', `modal--${size}`, `modal--${animationState}`, className), children: _jsx("div", { className: classNames('modal__container', `modal__container--${animationState}`, {
|
|
37
|
+
modal__container_fullScreen: isMobile && isMobileFullScreen,
|
|
38
|
+
[`modal__container_fullScreen--${animationState}`]: isMobile && isMobileFullScreen
|
|
39
|
+
}), ref: setContainerRef, children: _jsx(ModalContent, Object.assign({}, rest, { onClose: onClose })) }) }));
|
|
70
40
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { TModalConfirmationPropTypes } from './types';
|
|
3
|
-
export declare const ModalConfirmation: (
|
|
3
|
+
export declare const ModalConfirmation: ({ isOpen, onClose, onSubmit, title, className, size, buttonProps, dataIdPrefix, closeOnOutsideClick, iconProps, subtitle }: TModalConfirmationPropTypes) => ReactElement | null;
|
|
@@ -1,36 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useId, useState } from 'react';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
|
-
import { motion } from 'motion/react';
|
|
5
|
-
import { AnimatePresenceWrapper } from '../../helperComponents/AnimatePresenceWrapper';
|
|
6
4
|
import { useHideBodyScroll, useOnOutsideClick } from '../../hooks';
|
|
5
|
+
import { useAnimation } from '../../hooks/useAnimation';
|
|
7
6
|
import { Button } from '../Button';
|
|
8
7
|
import { Text } from '../Text';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
duration: 0.2
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
transition: {
|
|
20
|
-
duration: 0.4,
|
|
21
|
-
type: 'spring',
|
|
22
|
-
damping: 55,
|
|
23
|
-
stiffness: 700
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
export const ModalConfirmation = (props) => {
|
|
27
|
-
const { isOpen, onClose, onSubmit, title, className = '', size = 'small', buttonProps, dataIdPrefix, closeOnOutsideClick = true, iconProps, subtitle } = props;
|
|
8
|
+
import { useEscapeKey } from '../../hooks/useEscapeKey';
|
|
9
|
+
export const ModalConfirmation = ({ isOpen, onClose, onSubmit, title, className = '', size = 'small', buttonProps, dataIdPrefix, closeOnOutsideClick = true, iconProps, subtitle }) => {
|
|
10
|
+
const { animationState, shouldRender } = useAnimation({
|
|
11
|
+
isOpen,
|
|
12
|
+
enterDuration: 400,
|
|
13
|
+
exitDuration: 200
|
|
14
|
+
});
|
|
28
15
|
const [containerRef, setContainerRef] = useState(null);
|
|
29
16
|
useOnOutsideClick(containerRef, onClose, closeOnOutsideClick && isOpen, useId());
|
|
30
17
|
useHideBodyScroll(isOpen);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
18
|
+
useEscapeKey(onClose, { enabled: isOpen });
|
|
19
|
+
if (!shouldRender) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return (_jsx("div", { className: classnames('modal modal--confirmation', `modal--${size}`, `modal--${animationState}`, className), children: _jsx("div", { className: classnames('modal__container', 'text-center', `modal__container--${animationState}`), ref: setContainerRef, children: _jsxs("div", { className: 'modal__content', children: [(iconProps === null || iconProps === void 0 ? void 0 : iconProps.Component) ? (_jsx("div", { className: "modal__icon mb-32", children: _jsx(iconProps.Component, { size: 'xlarge' }) })) : null, title ? (_jsx(Text, { weight: "bolder", lineHeight: "large", size: "large", dataId: dataIdPrefix ? `${dataIdPrefix}-modal-title` : '', children: title })) : null, subtitle ? _jsx(Text, { className: 'mt-12', children: subtitle }) : null, buttonProps ? (_jsxs("div", { className: "modal__footer mt-32", children: [_jsx(Button, Object.assign({ type: "secondary", className: "modal__footer__btn mr-16", onClick: onClose, dataId: dataIdPrefix ? `${dataIdPrefix}-modal-cancel-button` : '' }, (buttonProps.cancel || {}))), _jsx(Button, Object.assign({ type: "danger", className: 'modal__footer__btn', onClick: onSubmit, dataId: dataIdPrefix ? `${dataIdPrefix}-modal-confirm-button` : '' }, buttonProps.confirm))] })) : null] }) }) }));
|
|
36
23
|
};
|
|
@@ -8,8 +8,9 @@ import { DROPDOWN_HEIGHT, DROPDOWN_WIDTH, ITEM_SIZE, ITEM_SIZE_MOBILE } from '..
|
|
|
8
8
|
import classNames from 'classnames';
|
|
9
9
|
import { noop } from '../../../../utils/helpers';
|
|
10
10
|
export const MultiBase = (props) => {
|
|
11
|
-
const { isMobile, closeDropdown, scrollableContentStyle, options, helperText, translations, onItemSelect, onItemDeselect, isSearchAvailable, setSelectedValues, selectedValues, labelLeftIconProps, labelRightIconComponent, optionRightIconComponent, maxSelectCount, menuOptions, dataIdPrefix, dropdownWidth } = props;
|
|
11
|
+
const { isMobile, closeDropdown, scrollableContentStyle, options, helperText, translations, onItemSelect, onItemDeselect, isSearchAvailable, setSelectedValues, selectedValues, labelLeftIconProps, labelRightIconComponent, optionRightIconComponent, maxSelectCount, menuOptions, dataIdPrefix, dropdownWidth, applySelectedItems } = props;
|
|
12
12
|
const { emptyListMainMessage, emptyListSecondaryMessage } = translations || {};
|
|
13
|
+
const [navigationMode, setNavigationMode] = useState(false);
|
|
13
14
|
const [searchValue, setSearchValue] = useState('');
|
|
14
15
|
const [isAllSelected, setAllSelected] = useState(false);
|
|
15
16
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
@@ -20,28 +21,39 @@ export const MultiBase = (props) => {
|
|
|
20
21
|
case 'ArrowDown':
|
|
21
22
|
e.preventDefault();
|
|
22
23
|
setActiveIndex((prev) => Math.min(prev + 1, filteredData.length - 1));
|
|
24
|
+
setNavigationMode(true);
|
|
23
25
|
break;
|
|
24
26
|
case 'ArrowUp':
|
|
25
27
|
e.preventDefault();
|
|
26
28
|
setActiveIndex((prev) => Math.max(prev - 1, 0));
|
|
29
|
+
setNavigationMode(true);
|
|
30
|
+
break;
|
|
31
|
+
case ' ':
|
|
32
|
+
if (navigationMode && activeIndex !== null) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
const item = filteredData[activeIndex];
|
|
35
|
+
if (!item) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const isSelected = checkIsSelected(item.value);
|
|
39
|
+
if (isSelected) {
|
|
40
|
+
onDeselect(item);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
onItemSelect(item);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
27
46
|
break;
|
|
28
47
|
case 'Enter':
|
|
29
48
|
e.preventDefault();
|
|
30
|
-
|
|
31
|
-
if (!item) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const isSelected = checkIsSelected(item.value);
|
|
35
|
-
if (isSelected) {
|
|
36
|
-
onDeselect(item);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
onItemSelect(item);
|
|
40
|
-
}
|
|
49
|
+
applySelectedItems();
|
|
41
50
|
break;
|
|
42
51
|
case 'Escape':
|
|
43
52
|
closeDropdown();
|
|
44
53
|
break;
|
|
54
|
+
default:
|
|
55
|
+
// any typing key exits navigation mode
|
|
56
|
+
setNavigationMode(false);
|
|
45
57
|
}
|
|
46
58
|
};
|
|
47
59
|
useEffect(() => {
|
|
@@ -63,6 +63,6 @@ export const MultiSelect = forwardRef((props, _ref) => {
|
|
|
63
63
|
// @ts-ignore
|
|
64
64
|
, Object.assign({
|
|
65
65
|
// @ts-ignore
|
|
66
|
-
options: options, isOpen: isOpen, translations: localizations, setIsOpen: setIsOpen, dropdownRef: dropdownRef, openDropdown: openDropdown, selectedValues: selectedValues, setSelectedValues: setSelectedValues, containerRef: containerRef, dropdownWidth: dropdownWidth, isMobileFullScreen: isMobileFullScreen }, rest)), options.length && !(isMobile && isMobileFullScreen) ? (_jsx(Footer, { checkboxInfo: checkboxInfo, hasChange: hasChange, buttonProps: footerButtonProps, onCancel: cancelSelectedItems, onApply: applySelectedItems, language: language })) : null] }) }));
|
|
66
|
+
options: options, isOpen: isOpen, translations: localizations, setIsOpen: setIsOpen, dropdownRef: dropdownRef, openDropdown: openDropdown, selectedValues: selectedValues, setSelectedValues: setSelectedValues, containerRef: containerRef, dropdownWidth: dropdownWidth, isMobileFullScreen: isMobileFullScreen, applySelectedItems: applySelectedItems }, rest)), options.length && !(isMobile && isMobileFullScreen) ? (_jsx(Footer, { checkboxInfo: checkboxInfo, hasChange: hasChange, buttonProps: footerButtonProps, onCancel: cancelSelectedItems, onApply: applySelectedItems, language: language })) : null] }) }));
|
|
67
67
|
});
|
|
68
68
|
MultiSelect.displayName = 'MultiSelect';
|
|
@@ -66,6 +66,7 @@ interface TMultiSelectCompProps extends IFormCompProps, TSelectBaseProps {
|
|
|
66
66
|
}
|
|
67
67
|
export interface TMultiSingleTabPropTypes extends TMultiSelectCompProps {
|
|
68
68
|
options: TSelectOptions;
|
|
69
|
+
applySelectedItems: () => void;
|
|
69
70
|
}
|
|
70
71
|
export interface TMultiSelectGroupedProps extends TMultiSelectCompProps {
|
|
71
72
|
options: TSelectGroupOptions;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type AnimationState = 'entering' | 'entered' | 'exiting' | 'exited';
|
|
2
|
+
interface UseAnimationOptions {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
enterDuration?: number;
|
|
5
|
+
exitDuration?: number;
|
|
6
|
+
onExitComplete?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const useAnimation: ({ isOpen, enterDuration, exitDuration, onExitComplete }: UseAnimationOptions) => {
|
|
9
|
+
animationState: AnimationState;
|
|
10
|
+
shouldRender: boolean;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export const useAnimation = ({ isOpen, enterDuration = 400, exitDuration = 200, onExitComplete }) => {
|
|
3
|
+
const [animationState, setAnimationState] = useState(isOpen ? 'entered' : 'exited');
|
|
4
|
+
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (isOpen) {
|
|
7
|
+
setShouldRender(true);
|
|
8
|
+
// Start entering animation
|
|
9
|
+
setAnimationState('entering');
|
|
10
|
+
// After a brief moment, mark as entered
|
|
11
|
+
const enterTimer = setTimeout(() => {
|
|
12
|
+
setAnimationState('entered');
|
|
13
|
+
}, 10);
|
|
14
|
+
return () => {
|
|
15
|
+
clearTimeout(enterTimer);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
// Start exit animation
|
|
20
|
+
setAnimationState('exiting');
|
|
21
|
+
// After exit duration, remove from DOM and call callback
|
|
22
|
+
const exitTimer = setTimeout(() => {
|
|
23
|
+
setAnimationState('exited');
|
|
24
|
+
setShouldRender(false);
|
|
25
|
+
onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete();
|
|
26
|
+
}, exitDuration);
|
|
27
|
+
return () => {
|
|
28
|
+
clearTimeout(exitTimer);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}, [isOpen, exitDuration, onExitComplete]);
|
|
32
|
+
return { animationState, shouldRender };
|
|
33
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
export function useEscapeKey(onEscape, { enabled = true } = {}) {
|
|
3
|
+
useEffect(() => {
|
|
4
|
+
if (!enabled)
|
|
5
|
+
return;
|
|
6
|
+
const handleKeyDown = (event) => {
|
|
7
|
+
if (event.key === 'Escape') {
|
|
8
|
+
onEscape();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
12
|
+
return () => {
|
|
13
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
14
|
+
};
|
|
15
|
+
}, [onEscape, enabled]);
|
|
16
|
+
}
|