@lumx/react 3.10.1-alpha.7 → 3.11.0
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/index.d.ts +86 -12
- package/index.js +318 -304
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/alert-dialog/AlertDialog.tsx +6 -3
- package/src/components/autocomplete/Autocomplete.stories.tsx +1 -2
- package/src/components/autocomplete/Autocomplete.tsx +3 -3
- package/src/components/autocomplete/AutocompleteMultiple.stories.tsx +2 -5
- package/src/components/autocomplete/AutocompleteMultiple.tsx +2 -2
- package/src/components/avatar/Avatar.tsx +3 -3
- package/src/components/badge/Badge.tsx +3 -3
- package/src/components/badge/BadgeWrapper.tsx +3 -2
- package/src/components/button/Button.tsx +9 -8
- package/src/components/button/ButtonGroup.tsx +9 -3
- package/src/components/button/ButtonRoot.tsx +6 -2
- package/src/components/button/IconButton.tsx +2 -2
- package/src/components/checkbox/Checkbox.tsx +4 -4
- package/src/components/chip/Chip.tsx +15 -9
- package/src/components/chip/ChipGroup.tsx +3 -2
- package/src/components/comment-block/CommentBlock.stories.tsx +4 -7
- package/src/components/comment-block/CommentBlock.tsx +3 -3
- package/src/components/date-picker/constants.ts +2 -2
- package/src/components/dialog/Dialog.tsx +9 -7
- package/src/components/divider/Divider.tsx +3 -3
- package/src/components/drag-handle/DragHandle.tsx +3 -3
- package/src/components/dropdown/Dropdown.tsx +4 -3
- package/src/components/expansion-panel/ExpansionPanel.tsx +26 -20
- package/src/components/flag/Flag.tsx +3 -3
- package/src/components/flex-box/FlexBox.tsx +4 -4
- package/src/components/generic-block/GenericBlock.tsx +10 -8
- package/src/components/generic-block/constants.ts +4 -9
- package/src/components/grid/Grid.tsx +5 -3
- package/src/components/grid/GridItem.tsx +5 -3
- package/src/components/grid-column/GridColumn.tsx +5 -3
- package/src/components/heading/Heading.tsx +7 -2
- package/src/components/icon/Icon.tsx +3 -3
- package/src/components/image-block/ImageBlock.tsx +3 -3
- package/src/components/image-lightbox/ImageLightbox.tsx +1 -1
- package/src/components/image-lightbox/constants.ts +2 -2
- package/src/components/image-lightbox/internal/ImageSlide.tsx +1 -1
- package/src/components/image-lightbox/internal/ImageSlideshow.tsx +9 -5
- package/src/components/image-lightbox/useImageLightbox.tsx +2 -1
- package/src/components/inline-list/InlineList.tsx +7 -3
- package/src/components/input-helper/InputHelper.tsx +3 -3
- package/src/components/input-label/InputLabel.tsx +3 -3
- package/src/components/lightbox/Lightbox.tsx +6 -4
- package/src/components/link/Link.tsx +11 -7
- package/src/components/link-preview/LinkPreview.tsx +3 -3
- package/src/components/list/List.tsx +4 -4
- package/src/components/list/ListDivider.tsx +3 -2
- package/src/components/list/ListItem.tsx +6 -5
- package/src/components/list/ListSubheader.tsx +3 -2
- package/src/components/list/useInteractiveList.tsx +7 -6
- package/src/components/message/Message.tsx +3 -3
- package/src/components/mosaic/Mosaic.test.tsx +3 -3
- package/src/components/mosaic/Mosaic.tsx +6 -5
- package/src/components/navigation/Navigation.stories.tsx +2 -2
- package/src/components/navigation/Navigation.tsx +3 -3
- package/src/components/navigation/NavigationItem.tsx +3 -9
- package/src/components/navigation/NavigationSection.tsx +3 -3
- package/src/components/notification/Notification.tsx +9 -5
- package/src/components/popover/Popover.stories.tsx +13 -15
- package/src/components/popover/Popover.test.tsx +6 -1
- package/src/components/popover/Popover.tsx +6 -6
- package/src/components/popover/usePopoverStyle.tsx +1 -3
- package/src/components/popover/useRestoreFocusOnClose.tsx +1 -1
- package/src/components/popover-dialog/PopoverDialog.tsx +3 -2
- package/src/components/post-block/PostBlock.tsx +11 -7
- package/src/components/progress/Progress.tsx +3 -3
- package/src/components/progress/ProgressCircular.tsx +3 -3
- package/src/components/progress/ProgressLinear.tsx +3 -3
- package/src/components/progress-tracker/ProgressTracker.stories.tsx +11 -11
- package/src/components/progress-tracker/ProgressTracker.tsx +4 -3
- package/src/components/progress-tracker/ProgressTrackerStep.tsx +3 -3
- package/src/components/progress-tracker/ProgressTrackerStepPanel.tsx +2 -0
- package/src/components/radio-button/RadioButton.tsx +3 -3
- package/src/components/radio-button/RadioGroup.stories.tsx +1 -4
- package/src/components/radio-button/RadioGroup.tsx +3 -2
- package/src/components/select/Select.stories.tsx +19 -38
- package/src/components/select/Select.tsx +5 -5
- package/src/components/select/SelectMultiple.stories.tsx +15 -30
- package/src/components/select/SelectMultiple.tsx +3 -4
- package/src/components/select/WithSelectContext.tsx +3 -4
- package/src/components/select/constants.ts +3 -1
- package/src/components/side-navigation/SideNavigation.stories.tsx +1 -1
- package/src/components/side-navigation/SideNavigation.tsx +4 -3
- package/src/components/side-navigation/SideNavigationItem.tsx +7 -7
- package/src/components/skeleton/SkeletonCircle.tsx +3 -3
- package/src/components/skeleton/SkeletonRectangle.tsx +3 -3
- package/src/components/skeleton/SkeletonTypography.stories.tsx +7 -12
- package/src/components/skeleton/SkeletonTypography.tsx +3 -3
- package/src/components/slider/Slider.tsx +4 -4
- package/src/components/slider/index.ts +1 -1
- package/src/components/slideshow/Slides.tsx +6 -4
- package/src/components/slideshow/Slideshow.stories.tsx +1 -3
- package/src/components/slideshow/Slideshow.tsx +3 -1
- package/src/components/slideshow/SlideshowControls.stories.tsx +1 -4
- package/src/components/slideshow/SlideshowControls.tsx +4 -4
- package/src/components/slideshow/SlideshowItem.tsx +5 -2
- package/src/components/slideshow/SlideshowItemGroup.tsx +5 -3
- package/src/components/switch/Switch.test.tsx +1 -1
- package/src/components/switch/Switch.tsx +7 -4
- package/src/components/table/Table.tsx +5 -3
- package/src/components/table/TableBody.tsx +7 -3
- package/src/components/table/TableCell.tsx +5 -3
- package/src/components/table/TableHeader.tsx +7 -3
- package/src/components/table/TableRow.tsx +5 -3
- package/src/components/tabs/TabList.tsx +1 -1
- package/src/components/tabs/TabPanel.tsx +2 -0
- package/src/components/tabs/Tabs.stories.tsx +12 -11
- package/src/components/text/Text.tsx +14 -5
- package/src/components/text-field/TextField.test.tsx +2 -2
- package/src/components/text-field/TextField.tsx +8 -7
- package/src/components/thumbnail/Thumbnail.tsx +4 -4
- package/src/components/toolbar/Toolbar.tsx +3 -3
- package/src/components/tooltip/Tooltip.tsx +4 -4
- package/src/components/tooltip/context.tsx +1 -1
- package/src/components/tooltip/useInjectTooltipRef.tsx +1 -1
- package/src/components/uploader/Uploader.tsx +3 -3
- package/src/components/user-block/UserBlock.tsx +12 -10
- package/src/hooks/useCallbackOnEscape.ts +1 -1
- package/src/hooks/useClickAway.tsx +2 -1
- package/src/hooks/useFocusTrap.ts +1 -1
- package/src/hooks/useInterval.tsx +4 -1
- package/src/hooks/useKeyboardListNavigation.tsx +4 -2
- package/src/hooks/useSizeOnWindowResize.ts +10 -14
- package/src/hooks/useStopPropagation.ts +2 -1
- package/src/stories/decorators/withCombinations.tsx +1 -1
- package/src/testing/utils/commonTestsSuiteRTL.tsx +2 -2
- package/src/utils/ClickAwayProvider/ClickAwayProvider.tsx +4 -0
- package/src/utils/className/getRootClassName.test.ts +11 -0
- package/src/utils/className/getRootClassName.ts +24 -0
- package/src/utils/className/index.ts +1 -0
- package/src/utils/date/getMonthCalendar.ts +4 -3
- package/src/utils/{makeListenerTowerContext.ts → function/makeListenerTowerContext.ts} +2 -2
- package/src/utils/{collection/partitionMulti.ts → partitionMulti.ts} +12 -13
- package/src/utils/{flattenChildren.ts → react/flattenChildren.ts} +3 -2
- package/src/utils/{renderButtonOrLink.tsx → react/renderButtonOrLink.tsx} +1 -1
- package/src/utils/{skipRender.tsx → react/skipRender.tsx} +1 -1
- package/src/utils/type/index.ts +18 -18
- package/src/utils/type/isComponent.ts +33 -0
- package/utils/index.d.ts +4 -0
- package/utils/index.js +96 -1
- package/utils/index.js.map +1 -1
- package/_internal/index.js +0 -99
- package/_internal/index.js.map +0 -1
- package/src/utils/className.test.js +0 -41
- package/src/utils/collection/castArray.test.ts +0 -15
- package/src/utils/collection/castArray.ts +0 -3
- package/src/utils/collection/chunk.test.ts +0 -15
- package/src/utils/collection/chunk.ts +0 -6
- package/src/utils/collection/isEmpty.test.js +0 -20
- package/src/utils/collection/isEmpty.ts +0 -4
- package/src/utils/collection/last.ts +0 -2
- package/src/utils/collection/partitionMulti.test.ts +0 -35
- package/src/utils/collection/pull.test.ts +0 -17
- package/src/utils/collection/pull.ts +0 -7
- package/src/utils/collection/range.test.js +0 -9
- package/src/utils/collection/range.ts +0 -2
- package/src/utils/function/memoize.test.ts +0 -36
- package/src/utils/function/memoize.ts +0 -13
- package/src/utils/type/ComponentClassName.ts +0 -7
- package/src/utils/type/KebabCase.ts +0 -6
- /package/src/utils/{clamp.ts → number/clamp.ts} +0 -0
- /package/src/utils/{OnBeforeUnmount.tsx → react/OnBeforeUnmount.tsx} +0 -0
- /package/src/utils/{mergeRefs.ts → react/mergeRefs.ts} +0 -0
- /package/src/utils/{renderLink.tsx → react/renderLink.tsx} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import { Children, Key, ReactChild, ReactNode, cloneElement, isValidElement } from 'react';
|
|
2
3
|
import { isFragment } from 'react-is';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -16,7 +17,7 @@ import { isFragment } from 'react-is';
|
|
|
16
17
|
export function flattenChildren(children: ReactNode) {
|
|
17
18
|
function recur(nodes: ReactNode, keys: Key[] = []) {
|
|
18
19
|
return Children.toArray(nodes).reduce((acc: ReactChild[], node, index) => {
|
|
19
|
-
const nodeKeys = keys.concat((node
|
|
20
|
+
const nodeKeys = keys.concat(get(node, 'key') ?? index);
|
|
20
21
|
if (isFragment(node)) {
|
|
21
22
|
acc.push(...recur(node.props.children, nodeKeys));
|
|
22
23
|
} else if (isValidElement(node)) {
|
package/src/utils/type/index.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
export { Callback } from './Callback';
|
|
2
|
-
export { Comp } from './Comp';
|
|
3
|
-
export { ComponentRef } from './ComponentRef';
|
|
4
|
-
export { Falsy } from './Falsy';
|
|
5
|
-
export { GenericProps } from './GenericProps';
|
|
6
|
-
export { HasAriaLabelOrLabelledBy } from './HasAriaLabelOrLabelledBy';
|
|
7
|
-
export { HasClassName } from './HasClassName';
|
|
8
|
-
export { HasCloseMode } from './HasCloseMode';
|
|
9
|
-
export { HasPolymorphicAs } from './HasPolymorphicAs';
|
|
10
|
-
export { HasTheme } from './HasTheme';
|
|
11
|
-
export { HeadingElement } from './HeadingElement';
|
|
1
|
+
export type { Callback } from './Callback';
|
|
2
|
+
export type { Comp } from './Comp';
|
|
3
|
+
export type { ComponentRef } from './ComponentRef';
|
|
4
|
+
export type { Falsy } from './Falsy';
|
|
5
|
+
export type { GenericProps } from './GenericProps';
|
|
6
|
+
export type { HasAriaLabelOrLabelledBy } from './HasAriaLabelOrLabelledBy';
|
|
7
|
+
export type { HasClassName } from './HasClassName';
|
|
8
|
+
export type { HasCloseMode } from './HasCloseMode';
|
|
9
|
+
export type { HasPolymorphicAs } from './HasPolymorphicAs';
|
|
10
|
+
export type { HasTheme } from './HasTheme';
|
|
11
|
+
export type { HeadingElement } from './HeadingElement';
|
|
12
|
+
export { isComponent } from './isComponent';
|
|
12
13
|
export { isComponentType } from './isComponentType';
|
|
13
|
-
export { MaybeElementOrRef } from './MaybeElementOrRef';
|
|
14
|
-
export { Point } from './Point';
|
|
15
|
-
export { Predicate } from './Predicate';
|
|
16
|
-
export { RectSize } from './RectSize';
|
|
17
|
-
export { TextElement } from './TextElement';
|
|
18
|
-
export { ValueOf } from './ValueOf';
|
|
19
|
-
export { ComponentClassName } from './ComponentClassName';
|
|
14
|
+
export type { MaybeElementOrRef } from './MaybeElementOrRef';
|
|
15
|
+
export type { Point } from './Point';
|
|
16
|
+
export type { Predicate } from './Predicate';
|
|
17
|
+
export type { RectSize } from './RectSize';
|
|
18
|
+
export type { TextElement } from './TextElement';
|
|
19
|
+
export type { ValueOf } from './ValueOf';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import get from 'lodash/get';
|
|
3
|
+
import type { Comp } from './Comp';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Properties of a component to use to determine it's name.
|
|
7
|
+
* In the order of preference.
|
|
8
|
+
*/
|
|
9
|
+
const NAME_PROPERTIES: string[] = [
|
|
10
|
+
'type',
|
|
11
|
+
'type.displayName',
|
|
12
|
+
'displayName',
|
|
13
|
+
'name',
|
|
14
|
+
'type.name',
|
|
15
|
+
'props.mdxType',
|
|
16
|
+
'_reactInternalFiber.elementType.name',
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Create a predicate function that checks if a ReactNode is a react element from the given component.
|
|
20
|
+
*
|
|
21
|
+
* @param component React function component or the component name
|
|
22
|
+
* @return predicate returning true if value is instance of the component
|
|
23
|
+
*/
|
|
24
|
+
export const isComponent =
|
|
25
|
+
<C>(component: Comp<C, any> | string) =>
|
|
26
|
+
(instance: ReactNode): instance is ReactElement => {
|
|
27
|
+
const componentName = typeof component === 'string' ? component : component.displayName;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
!!get(instance, '$$typeof') &&
|
|
31
|
+
NAME_PROPERTIES.some((nameProperty: string): boolean => get(instance, nameProperty) === componentName)
|
|
32
|
+
);
|
|
33
|
+
};
|
package/utils/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ interface ClickAwayProviderProps extends ClickAwayParameters {
|
|
|
17
17
|
* (Optional) Element that should be considered as part of the parent
|
|
18
18
|
*/
|
|
19
19
|
parentRef?: RefObject<HTMLElement>;
|
|
20
|
+
/**
|
|
21
|
+
* Children
|
|
22
|
+
*/
|
|
23
|
+
children?: React.ReactNode;
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
26
|
* Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure
|
package/utils/index.js
CHANGED
|
@@ -1,2 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
import React__default, { useEffect, useContext, useMemo, useRef, createContext } from 'react';
|
|
2
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
|
|
4
|
+
const EVENT_TYPES = ['mousedown', 'touchstart'];
|
|
5
|
+
function isClickAway(target, refs) {
|
|
6
|
+
// The target element is not contained in any of the listed element references.
|
|
7
|
+
return !refs.some(e => {
|
|
8
|
+
var _e$current;
|
|
9
|
+
return e === null || e === void 0 ? void 0 : (_e$current = e.current) === null || _e$current === void 0 ? void 0 : _e$current.contains(target);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Listen to clicks away from the given elements and callback the passed in function.
|
|
14
|
+
*
|
|
15
|
+
* Warning: If you need to detect click away on nested React portals, please use the `ClickAwayProvider` component.
|
|
16
|
+
*/
|
|
17
|
+
function useClickAway(_ref) {
|
|
18
|
+
let {
|
|
19
|
+
callback,
|
|
20
|
+
childrenRefs
|
|
21
|
+
} = _ref;
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const {
|
|
24
|
+
current: currentRefs
|
|
25
|
+
} = childrenRefs;
|
|
26
|
+
if (!callback || !currentRefs || isEmpty(currentRefs)) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const listener = evt => {
|
|
30
|
+
if (isClickAway(evt.target, currentRefs)) {
|
|
31
|
+
callback(evt);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
EVENT_TYPES.forEach(evtType => document.addEventListener(evtType, listener));
|
|
35
|
+
return () => {
|
|
36
|
+
EVENT_TYPES.forEach(evtType => document.removeEventListener(evtType, listener));
|
|
37
|
+
};
|
|
38
|
+
}, [callback, childrenRefs]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ClickAwayAncestorContext = /*#__PURE__*/createContext(null);
|
|
42
|
+
/**
|
|
43
|
+
* Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure
|
|
44
|
+
* we take into account both the DOM tree and the React tree to detect click away.
|
|
45
|
+
*
|
|
46
|
+
* @return the react component.
|
|
47
|
+
*/
|
|
48
|
+
const ClickAwayProvider = _ref => {
|
|
49
|
+
let {
|
|
50
|
+
children,
|
|
51
|
+
callback,
|
|
52
|
+
childrenRefs,
|
|
53
|
+
parentRef
|
|
54
|
+
} = _ref;
|
|
55
|
+
const parentContext = useContext(ClickAwayAncestorContext);
|
|
56
|
+
const currentContext = useMemo(() => {
|
|
57
|
+
const context = {
|
|
58
|
+
childrenRefs: [],
|
|
59
|
+
/**
|
|
60
|
+
* Add element refs to the current context and propagate to the parent context.
|
|
61
|
+
*/
|
|
62
|
+
addRefs() {
|
|
63
|
+
// Add element refs that should be considered as inside the click away context.
|
|
64
|
+
context.childrenRefs.push(...arguments);
|
|
65
|
+
if (parentContext) {
|
|
66
|
+
// Also add then to the parent context
|
|
67
|
+
parentContext.addRefs(...arguments);
|
|
68
|
+
if (parentRef) {
|
|
69
|
+
// The parent element is also considered as inside the parent click away context but not inside the current context
|
|
70
|
+
parentContext.addRefs(parentRef);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return context;
|
|
76
|
+
}, [parentContext, parentRef]);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const {
|
|
79
|
+
current: currentRefs
|
|
80
|
+
} = childrenRefs;
|
|
81
|
+
if (!currentRefs) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
currentContext.addRefs(...currentRefs);
|
|
85
|
+
}, [currentContext, childrenRefs]);
|
|
86
|
+
useClickAway({
|
|
87
|
+
callback,
|
|
88
|
+
childrenRefs: useRef(currentContext.childrenRefs)
|
|
89
|
+
});
|
|
90
|
+
return /*#__PURE__*/React__default.createElement(ClickAwayAncestorContext.Provider, {
|
|
91
|
+
value: currentContext
|
|
92
|
+
}, children);
|
|
93
|
+
};
|
|
94
|
+
ClickAwayProvider.displayName = 'ClickAwayProvider';
|
|
95
|
+
|
|
96
|
+
export { ClickAwayProvider };
|
|
2
97
|
//# sourceMappingURL=index.js.map
|
package/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/hooks/useClickAway.tsx","../../src/utils/ClickAwayProvider/ClickAwayProvider.tsx"],"sourcesContent":["import { RefObject, useEffect } from 'react';\n\nimport { Falsy } from '@lumx/react/utils/type';\n\nimport isEmpty from 'lodash/isEmpty';\n\nconst EVENT_TYPES = ['mousedown', 'touchstart'];\n\nfunction isClickAway(target: HTMLElement, refs: Array<RefObject<HTMLElement>>): boolean {\n // The target element is not contained in any of the listed element references.\n return !refs.some((e) => e?.current?.contains(target));\n}\n\nexport interface ClickAwayParameters {\n /**\n * A callback function to call when the user clicks away from the elements.\n */\n callback: EventListener | Falsy;\n /**\n * Elements considered within the click away context (clicking outside them will trigger the click away callback).\n */\n childrenRefs: RefObject<Array<RefObject<HTMLElement>>>;\n}\n\n/**\n * Listen to clicks away from the given elements and callback the passed in function.\n *\n * Warning: If you need to detect click away on nested React portals, please use the `ClickAwayProvider` component.\n */\nexport function useClickAway({ callback, childrenRefs }: ClickAwayParameters): void {\n useEffect(() => {\n const { current: currentRefs } = childrenRefs;\n if (!callback || !currentRefs || isEmpty(currentRefs)) {\n return undefined;\n }\n const listener: EventListener = (evt) => {\n if (isClickAway(evt.target as HTMLElement, currentRefs)) {\n callback(evt);\n }\n };\n\n EVENT_TYPES.forEach((evtType) => document.addEventListener(evtType, listener));\n return () => {\n EVENT_TYPES.forEach((evtType) => document.removeEventListener(evtType, listener));\n };\n }, [callback, childrenRefs]);\n}\n","import React, { createContext, RefObject, useContext, useEffect, useMemo, useRef } from 'react';\nimport { ClickAwayParameters, useClickAway } from '@lumx/react/hooks/useClickAway';\n\ninterface ContextValue {\n childrenRefs: Array<RefObject<HTMLElement>>;\n addRefs(...newChildrenRefs: Array<RefObject<HTMLElement>>): void;\n}\n\nconst ClickAwayAncestorContext = createContext<ContextValue | null>(null);\n\ninterface ClickAwayProviderProps extends ClickAwayParameters {\n /**\n * (Optional) Element that should be considered as part of the parent\n */\n parentRef?: RefObject<HTMLElement>;\n /**\n * Children\n */\n children?: React.ReactNode;\n}\n\n/**\n * Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure\n * we take into account both the DOM tree and the React tree to detect click away.\n *\n * @return the react component.\n */\nexport const ClickAwayProvider: React.FC<ClickAwayProviderProps> = ({\n children,\n callback,\n childrenRefs,\n parentRef,\n}) => {\n const parentContext = useContext(ClickAwayAncestorContext);\n const currentContext = useMemo(() => {\n const context: ContextValue = {\n childrenRefs: [],\n /**\n * Add element refs to the current context and propagate to the parent context.\n */\n addRefs(...newChildrenRefs) {\n // Add element refs that should be considered as inside the click away context.\n context.childrenRefs.push(...newChildrenRefs);\n\n if (parentContext) {\n // Also add then to the parent context\n parentContext.addRefs(...newChildrenRefs);\n if (parentRef) {\n // The parent element is also considered as inside the parent click away context but not inside the current context\n parentContext.addRefs(parentRef);\n }\n }\n },\n };\n return context;\n }, [parentContext, parentRef]);\n\n useEffect(() => {\n const { current: currentRefs } = childrenRefs;\n if (!currentRefs) {\n return;\n }\n currentContext.addRefs(...currentRefs);\n }, [currentContext, childrenRefs]);\n\n useClickAway({ callback, childrenRefs: useRef(currentContext.childrenRefs) });\n return <ClickAwayAncestorContext.Provider value={currentContext}>{children}</ClickAwayAncestorContext.Provider>;\n};\nClickAwayProvider.displayName = 'ClickAwayProvider';\n"],"names":["EVENT_TYPES","isClickAway","target","refs","some","e","_e$current","current","contains","useClickAway","_ref","callback","childrenRefs","useEffect","currentRefs","isEmpty","undefined","listener","evt","forEach","evtType","document","addEventListener","removeEventListener","ClickAwayAncestorContext","createContext","ClickAwayProvider","children","parentRef","parentContext","useContext","currentContext","useMemo","context","addRefs","push","arguments","useRef","React","createElement","Provider","value","displayName"],"mappings":"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"}
|
package/_internal/index.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import React__default, { useEffect, useContext, useMemo, useRef, createContext } from 'react';
|
|
2
|
-
|
|
3
|
-
/** Check if object or array is empty (true on falsy values) */
|
|
4
|
-
const isEmpty = obj => !obj || Object.entries(obj).length === 0;
|
|
5
|
-
|
|
6
|
-
const EVENT_TYPES = ['mousedown', 'touchstart'];
|
|
7
|
-
function isClickAway(target, refs) {
|
|
8
|
-
// The target element is not contained in any of the listed element references.
|
|
9
|
-
return !refs.some(e => {
|
|
10
|
-
var _e$current;
|
|
11
|
-
return e === null || e === void 0 ? void 0 : (_e$current = e.current) === null || _e$current === void 0 ? void 0 : _e$current.contains(target);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Listen to clicks away from the given elements and callback the passed in function.
|
|
16
|
-
*
|
|
17
|
-
* Warning: If you need to detect click away on nested React portals, please use the `ClickAwayProvider` component.
|
|
18
|
-
*/
|
|
19
|
-
function useClickAway(_ref) {
|
|
20
|
-
let {
|
|
21
|
-
callback,
|
|
22
|
-
childrenRefs
|
|
23
|
-
} = _ref;
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
const {
|
|
26
|
-
current: currentRefs
|
|
27
|
-
} = childrenRefs;
|
|
28
|
-
if (!callback || !currentRefs || isEmpty(currentRefs)) {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
const listener = evt => {
|
|
32
|
-
if (isClickAway(evt.target, currentRefs)) {
|
|
33
|
-
callback(evt);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
EVENT_TYPES.forEach(evtType => document.addEventListener(evtType, listener));
|
|
37
|
-
return () => {
|
|
38
|
-
EVENT_TYPES.forEach(evtType => document.removeEventListener(evtType, listener));
|
|
39
|
-
};
|
|
40
|
-
}, [callback, childrenRefs]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const ClickAwayAncestorContext = /*#__PURE__*/createContext(null);
|
|
44
|
-
/**
|
|
45
|
-
* Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure
|
|
46
|
-
* we take into account both the DOM tree and the React tree to detect click away.
|
|
47
|
-
*
|
|
48
|
-
* @return the react component.
|
|
49
|
-
*/
|
|
50
|
-
const ClickAwayProvider = _ref => {
|
|
51
|
-
let {
|
|
52
|
-
children,
|
|
53
|
-
callback,
|
|
54
|
-
childrenRefs,
|
|
55
|
-
parentRef
|
|
56
|
-
} = _ref;
|
|
57
|
-
const parentContext = useContext(ClickAwayAncestorContext);
|
|
58
|
-
const currentContext = useMemo(() => {
|
|
59
|
-
const context = {
|
|
60
|
-
childrenRefs: [],
|
|
61
|
-
/**
|
|
62
|
-
* Add element refs to the current context and propagate to the parent context.
|
|
63
|
-
*/
|
|
64
|
-
addRefs() {
|
|
65
|
-
// Add element refs that should be considered as inside the click away context.
|
|
66
|
-
context.childrenRefs.push(...arguments);
|
|
67
|
-
if (parentContext) {
|
|
68
|
-
// Also add then to the parent context
|
|
69
|
-
parentContext.addRefs(...arguments);
|
|
70
|
-
if (parentRef) {
|
|
71
|
-
// The parent element is also considered as inside the parent click away context but not inside the current context
|
|
72
|
-
parentContext.addRefs(parentRef);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
return context;
|
|
78
|
-
}, [parentContext, parentRef]);
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
const {
|
|
81
|
-
current: currentRefs
|
|
82
|
-
} = childrenRefs;
|
|
83
|
-
if (!currentRefs) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
currentContext.addRefs(...currentRefs);
|
|
87
|
-
}, [currentContext, childrenRefs]);
|
|
88
|
-
useClickAway({
|
|
89
|
-
callback,
|
|
90
|
-
childrenRefs: useRef(currentContext.childrenRefs)
|
|
91
|
-
});
|
|
92
|
-
return /*#__PURE__*/React__default.createElement(ClickAwayAncestorContext.Provider, {
|
|
93
|
-
value: currentContext
|
|
94
|
-
}, children);
|
|
95
|
-
};
|
|
96
|
-
ClickAwayProvider.displayName = 'ClickAwayProvider';
|
|
97
|
-
|
|
98
|
-
export { ClickAwayProvider as C, isEmpty as i };
|
|
99
|
-
//# sourceMappingURL=index.js.map
|
package/_internal/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/utils/collection/isEmpty.ts","../../src/hooks/useClickAway.tsx","../../src/utils/ClickAwayProvider/ClickAwayProvider.tsx"],"sourcesContent":["import { Falsy } from '../type';\n\n/** Check if object or array is empty (true on falsy values) */\nexport const isEmpty = (obj: object | Falsy) => !obj || Object.entries(obj).length === 0;\n","import { RefObject, useEffect } from 'react';\n\nimport { Falsy } from '@lumx/react/utils/type';\nimport { isEmpty } from '@lumx/react/utils/collection/isEmpty';\n\nconst EVENT_TYPES = ['mousedown', 'touchstart'];\n\nfunction isClickAway(target: HTMLElement, refs: Array<RefObject<HTMLElement>>): boolean {\n // The target element is not contained in any of the listed element references.\n return !refs.some((e) => e?.current?.contains(target));\n}\n\nexport interface ClickAwayParameters {\n /**\n * A callback function to call when the user clicks away from the elements.\n */\n callback: EventListener | Falsy;\n /**\n * Elements considered within the click away context (clicking outside them will trigger the click away callback).\n */\n childrenRefs: RefObject<Array<RefObject<HTMLElement>>>;\n}\n\n/**\n * Listen to clicks away from the given elements and callback the passed in function.\n *\n * Warning: If you need to detect click away on nested React portals, please use the `ClickAwayProvider` component.\n */\nexport function useClickAway({ callback, childrenRefs }: ClickAwayParameters): void {\n useEffect(() => {\n const { current: currentRefs } = childrenRefs;\n if (!callback || !currentRefs || isEmpty(currentRefs)) {\n return undefined;\n }\n const listener: EventListener = (evt) => {\n if (isClickAway(evt.target as HTMLElement, currentRefs)) {\n callback(evt);\n }\n };\n\n EVENT_TYPES.forEach((evtType) => document.addEventListener(evtType, listener));\n return () => {\n EVENT_TYPES.forEach((evtType) => document.removeEventListener(evtType, listener));\n };\n }, [callback, childrenRefs]);\n}\n","import React, { createContext, RefObject, useContext, useEffect, useMemo, useRef } from 'react';\nimport { ClickAwayParameters, useClickAway } from '@lumx/react/hooks/useClickAway';\n\ninterface ContextValue {\n childrenRefs: Array<RefObject<HTMLElement>>;\n addRefs(...newChildrenRefs: Array<RefObject<HTMLElement>>): void;\n}\n\nconst ClickAwayAncestorContext = createContext<ContextValue | null>(null);\n\ninterface ClickAwayProviderProps extends ClickAwayParameters {\n /**\n * (Optional) Element that should be considered as part of the parent\n */\n parentRef?: RefObject<HTMLElement>;\n}\n\n/**\n * Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure\n * we take into account both the DOM tree and the React tree to detect click away.\n *\n * @return the react component.\n */\nexport const ClickAwayProvider: React.FC<ClickAwayProviderProps> = ({\n children,\n callback,\n childrenRefs,\n parentRef,\n}) => {\n const parentContext = useContext(ClickAwayAncestorContext);\n const currentContext = useMemo(() => {\n const context: ContextValue = {\n childrenRefs: [],\n /**\n * Add element refs to the current context and propagate to the parent context.\n */\n addRefs(...newChildrenRefs) {\n // Add element refs that should be considered as inside the click away context.\n context.childrenRefs.push(...newChildrenRefs);\n\n if (parentContext) {\n // Also add then to the parent context\n parentContext.addRefs(...newChildrenRefs);\n if (parentRef) {\n // The parent element is also considered as inside the parent click away context but not inside the current context\n parentContext.addRefs(parentRef);\n }\n }\n },\n };\n return context;\n }, [parentContext, parentRef]);\n\n useEffect(() => {\n const { current: currentRefs } = childrenRefs;\n if (!currentRefs) {\n return;\n }\n currentContext.addRefs(...currentRefs);\n }, [currentContext, childrenRefs]);\n\n useClickAway({ callback, childrenRefs: useRef(currentContext.childrenRefs) });\n return <ClickAwayAncestorContext.Provider value={currentContext}>{children}</ClickAwayAncestorContext.Provider>;\n};\nClickAwayProvider.displayName = 'ClickAwayProvider';\n"],"names":["isEmpty","obj","Object","entries","length","EVENT_TYPES","isClickAway","target","refs","some","e","_e$current","current","contains","useClickAway","_ref","callback","childrenRefs","useEffect","currentRefs","undefined","listener","evt","forEach","evtType","document","addEventListener","removeEventListener","ClickAwayAncestorContext","createContext","ClickAwayProvider","children","parentRef","parentContext","useContext","currentContext","useMemo","context","addRefs","push","arguments","useRef","React","createElement","Provider","value","displayName"],"mappings":"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"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { getBasicClass, handleBasicClasses } from './className';
|
|
2
|
-
|
|
3
|
-
describe(getBasicClass, () => {
|
|
4
|
-
it('should generate boolean modifier name with boolean prefix', () => {
|
|
5
|
-
expect(getBasicClass({ prefix: 'prefix', type: 'foo', value: true })).toEqual('prefix--is-foo');
|
|
6
|
-
});
|
|
7
|
-
it('should generate boolean modifier name keeping the existing boolean prefix', () => {
|
|
8
|
-
expect(getBasicClass({ prefix: 'prefix', type: 'isFoo', value: true })).toEqual('prefix--is-foo');
|
|
9
|
-
expect(getBasicClass({ prefix: 'prefix', type: 'hasFoo', value: true })).toEqual('prefix--has-foo');
|
|
10
|
-
});
|
|
11
|
-
it(`should generate string modifier name`, () => {
|
|
12
|
-
expect(getBasicClass({ prefix: 'prefix', type: 'foo', value: 'bar' })).toEqual('prefix--foo-bar');
|
|
13
|
-
});
|
|
14
|
-
it(`should generate number modifier name`, () => {
|
|
15
|
-
expect(getBasicClass({ prefix: 'prefix', type: 'foo', value: 2 })).toEqual('prefix--foo-2');
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe(handleBasicClasses, () => {
|
|
20
|
-
it('should use prefix if there is no modifier', () => {
|
|
21
|
-
expect(
|
|
22
|
-
handleBasicClasses({
|
|
23
|
-
prefix: 'prefix',
|
|
24
|
-
}),
|
|
25
|
-
).toEqual('prefix');
|
|
26
|
-
});
|
|
27
|
-
it('should filter falsy modifiers', () => {
|
|
28
|
-
expect(
|
|
29
|
-
handleBasicClasses({
|
|
30
|
-
prefix: 'prefix',
|
|
31
|
-
theme: 'dark',
|
|
32
|
-
isModifier: true,
|
|
33
|
-
isEmpty: '',
|
|
34
|
-
isNull: null,
|
|
35
|
-
isUndefined: undefined,
|
|
36
|
-
isZero: 0,
|
|
37
|
-
isNumberNotZero: 2,
|
|
38
|
-
}),
|
|
39
|
-
).toEqual('prefix prefix--theme-dark prefix--is-modifier prefix--is-number-not-zero-2');
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { castArray } from '@lumx/react/utils/collection/castArray';
|
|
2
|
-
|
|
3
|
-
describe(castArray, () => {
|
|
4
|
-
it('should keep existing array', () => {
|
|
5
|
-
const input = [1, 2];
|
|
6
|
-
const output = castArray(input);
|
|
7
|
-
expect(output).toEqual([1, 2]);
|
|
8
|
-
expect(output).toBe(input);
|
|
9
|
-
});
|
|
10
|
-
it('should cast item to array', () => {
|
|
11
|
-
const input = 1;
|
|
12
|
-
const output = castArray(input);
|
|
13
|
-
expect(output).toEqual([1]);
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { chunk } from '@lumx/react/utils/collection/chunk';
|
|
2
|
-
|
|
3
|
-
describe(chunk, () => {
|
|
4
|
-
it('should do nothing on empty array', () => {
|
|
5
|
-
expect(chunk([], 2)).toEqual([]);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('should work with size larger than input array', () => {
|
|
9
|
-
expect(chunk([1, 2], 4)).toEqual([[1, 2]]);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should chunk array with size not perfectly dividing the array length', () => {
|
|
13
|
-
expect(chunk([1, 2, 3, 4, 5], 2)).toEqual([[1, 2], [3, 4], [5]]);
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/** Chunk array in slices of given size */
|
|
2
|
-
export function chunk<T>(input: Array<T>, size: number): T[][] {
|
|
3
|
-
return input.reduce((arr, item, idx) => {
|
|
4
|
-
return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
|
|
5
|
-
}, [] as T[][]);
|
|
6
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { isEmpty } from './isEmpty';
|
|
2
|
-
|
|
3
|
-
describe(isEmpty, () => {
|
|
4
|
-
it('should return true for falsy values', () => {
|
|
5
|
-
expect(isEmpty(undefined)).toBe(true);
|
|
6
|
-
expect(isEmpty(null)).toBe(true);
|
|
7
|
-
expect(isEmpty(0)).toBe(true);
|
|
8
|
-
expect(isEmpty('')).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should return true for empty object or array', () => {
|
|
12
|
-
expect(isEmpty([])).toBe(true);
|
|
13
|
-
expect(isEmpty({})).toBe(true);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should return false for non empty object or array', () => {
|
|
17
|
-
expect(isEmpty([''])).toBe(false);
|
|
18
|
-
expect(isEmpty({ foo: false })).toBe(false);
|
|
19
|
-
});
|
|
20
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { partitionMulti } from './partitionMulti';
|
|
2
|
-
|
|
3
|
-
describe('partitionMulti', () => {
|
|
4
|
-
it('should partition with single predicate', () => {
|
|
5
|
-
const data = [0, 1, 2, 3, 4, 5];
|
|
6
|
-
const isEven = (n: number): boolean => n % 2 === 0;
|
|
7
|
-
|
|
8
|
-
const actual = partitionMulti(data, [isEven]);
|
|
9
|
-
|
|
10
|
-
expect(actual).toEqual([
|
|
11
|
-
[0, 2, 4],
|
|
12
|
-
[1, 3, 5],
|
|
13
|
-
]);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should partition on multiple predicates', () => {
|
|
17
|
-
type T = string | number | boolean;
|
|
18
|
-
const data: T[] = ['a', 1, 'b', false, true];
|
|
19
|
-
const isString = (s: T): boolean => typeof s === 'string';
|
|
20
|
-
const isNumber = (s: T): boolean => typeof s === 'number';
|
|
21
|
-
const isNull = (s: T): boolean => s === null;
|
|
22
|
-
|
|
23
|
-
const partitions = partitionMulti(data, [isString, isNumber, isNull]);
|
|
24
|
-
expect(partitions).toEqual([
|
|
25
|
-
// strings
|
|
26
|
-
['a', 'b'],
|
|
27
|
-
// numbers
|
|
28
|
-
[1],
|
|
29
|
-
// nulls
|
|
30
|
-
[],
|
|
31
|
-
// others
|
|
32
|
-
[false, true],
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { pull } from '@lumx/react/utils/collection/pull';
|
|
2
|
-
|
|
3
|
-
describe(pull, () => {
|
|
4
|
-
it('should do nothing if element does not exist', () => {
|
|
5
|
-
const a = [1, 2];
|
|
6
|
-
pull(a, 0);
|
|
7
|
-
expect(a).toBe(a);
|
|
8
|
-
expect(a).toEqual([1, 2]);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should pull an element from the array', () => {
|
|
12
|
-
const a = [1, 2];
|
|
13
|
-
pull(a, 1);
|
|
14
|
-
expect(a).toBe(a);
|
|
15
|
-
expect(a).toEqual([2]);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { memoize } from '@lumx/react/utils/function/memoize';
|
|
2
|
-
|
|
3
|
-
describe(memoize, () => {
|
|
4
|
-
it('should memoize a function returning nothing', () => {
|
|
5
|
-
const fn = jest.fn();
|
|
6
|
-
const memoized = memoize(fn);
|
|
7
|
-
|
|
8
|
-
expect(memoized()).toEqual(undefined);
|
|
9
|
-
expect(memoized()).toEqual(undefined);
|
|
10
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should memoize a function with no args', () => {
|
|
14
|
-
const fn = jest.fn((i) => i);
|
|
15
|
-
const memoized = memoize(fn);
|
|
16
|
-
|
|
17
|
-
expect(memoized('value')).toEqual('value');
|
|
18
|
-
expect(memoized('value')).toEqual('value');
|
|
19
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
20
|
-
|
|
21
|
-
expect(memoized('another value')).toEqual('another value');
|
|
22
|
-
expect(fn).toHaveBeenCalledTimes(2);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should memoize a function with multiple args', () => {
|
|
26
|
-
const fn = jest.fn((a, b) => `${a} ${b}`);
|
|
27
|
-
const memoized = memoize(fn);
|
|
28
|
-
|
|
29
|
-
expect(memoized(1, true)).toEqual('1 true');
|
|
30
|
-
expect(memoized(1, true)).toEqual('1 true');
|
|
31
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
32
|
-
|
|
33
|
-
expect(memoized('foo', 4)).toEqual('foo 4');
|
|
34
|
-
expect(fn).toHaveBeenCalledTimes(2);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** Memoize a function based on the serialization of its args */
|
|
2
|
-
export function memoize<A extends Array<unknown>, R>(fn: (...args: A) => R): (...args: A) => R {
|
|
3
|
-
const cache = new Map<string, R>();
|
|
4
|
-
|
|
5
|
-
return (...args) => {
|
|
6
|
-
const serializedArgs = JSON.stringify(args);
|
|
7
|
-
if (cache.has(serializedArgs)) return cache.get(serializedArgs) as R;
|
|
8
|
-
|
|
9
|
-
const value = fn(...args);
|
|
10
|
-
cache.set(serializedArgs, value);
|
|
11
|
-
return value;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { KebabCase } from './KebabCase';
|
|
2
|
-
|
|
3
|
-
/** Transform the component name into the lumx class name. */
|
|
4
|
-
export type ComponentClassName<
|
|
5
|
-
TComponentName extends string,
|
|
6
|
-
TSubComponentName extends string = '',
|
|
7
|
-
> = `lumx-${KebabCase<TComponentName>}${TSubComponentName extends `${TComponentName}${infer TSubName}` ? `__${KebabCase<TSubName>}` : ''}`;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|