@lumx/react 3.10.1-alpha.6 → 3.10.1-alpha.8

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.
Files changed (166) hide show
  1. package/index.d.ts +86 -12
  2. package/index.js +299 -296
  3. package/index.js.map +1 -1
  4. package/package.json +3 -3
  5. package/src/components/alert-dialog/AlertDialog.tsx +6 -3
  6. package/src/components/autocomplete/Autocomplete.stories.tsx +1 -2
  7. package/src/components/autocomplete/Autocomplete.tsx +3 -3
  8. package/src/components/autocomplete/AutocompleteMultiple.stories.tsx +2 -5
  9. package/src/components/autocomplete/AutocompleteMultiple.tsx +2 -2
  10. package/src/components/avatar/Avatar.tsx +3 -3
  11. package/src/components/badge/Badge.tsx +3 -3
  12. package/src/components/badge/BadgeWrapper.tsx +3 -2
  13. package/src/components/button/Button.tsx +9 -8
  14. package/src/components/button/ButtonGroup.tsx +9 -3
  15. package/src/components/button/ButtonRoot.tsx +6 -2
  16. package/src/components/button/IconButton.tsx +2 -2
  17. package/src/components/checkbox/Checkbox.tsx +4 -4
  18. package/src/components/chip/Chip.tsx +15 -9
  19. package/src/components/chip/ChipGroup.tsx +3 -2
  20. package/src/components/comment-block/CommentBlock.stories.tsx +4 -7
  21. package/src/components/comment-block/CommentBlock.tsx +3 -3
  22. package/src/components/date-picker/constants.ts +2 -2
  23. package/src/components/dialog/Dialog.tsx +9 -7
  24. package/src/components/divider/Divider.tsx +3 -3
  25. package/src/components/drag-handle/DragHandle.tsx +3 -3
  26. package/src/components/dropdown/Dropdown.tsx +4 -3
  27. package/src/components/expansion-panel/ExpansionPanel.tsx +26 -20
  28. package/src/components/flag/Flag.tsx +3 -3
  29. package/src/components/flex-box/FlexBox.tsx +4 -4
  30. package/src/components/generic-block/GenericBlock.tsx +10 -8
  31. package/src/components/generic-block/constants.ts +4 -9
  32. package/src/components/grid/Grid.tsx +5 -3
  33. package/src/components/grid/GridItem.tsx +5 -3
  34. package/src/components/grid-column/GridColumn.tsx +5 -3
  35. package/src/components/heading/Heading.tsx +7 -2
  36. package/src/components/icon/Icon.tsx +3 -3
  37. package/src/components/image-block/ImageBlock.tsx +3 -3
  38. package/src/components/image-lightbox/ImageLightbox.tsx +1 -1
  39. package/src/components/image-lightbox/constants.ts +2 -2
  40. package/src/components/image-lightbox/internal/ImageSlide.tsx +1 -1
  41. package/src/components/image-lightbox/internal/ImageSlideshow.tsx +9 -5
  42. package/src/components/image-lightbox/useImageLightbox.tsx +2 -1
  43. package/src/components/inline-list/InlineList.tsx +7 -3
  44. package/src/components/input-helper/InputHelper.tsx +3 -3
  45. package/src/components/input-label/InputLabel.tsx +3 -3
  46. package/src/components/lightbox/Lightbox.tsx +6 -4
  47. package/src/components/link/Link.tsx +11 -7
  48. package/src/components/link-preview/LinkPreview.tsx +3 -3
  49. package/src/components/list/List.tsx +4 -4
  50. package/src/components/list/ListDivider.tsx +3 -2
  51. package/src/components/list/ListItem.tsx +6 -5
  52. package/src/components/list/ListSubheader.tsx +3 -2
  53. package/src/components/list/useInteractiveList.tsx +7 -6
  54. package/src/components/message/Message.tsx +3 -3
  55. package/src/components/mosaic/Mosaic.test.tsx +3 -3
  56. package/src/components/mosaic/Mosaic.tsx +6 -5
  57. package/src/components/navigation/Navigation.stories.tsx +2 -2
  58. package/src/components/navigation/Navigation.tsx +3 -3
  59. package/src/components/navigation/NavigationItem.tsx +3 -9
  60. package/src/components/navigation/NavigationSection.tsx +3 -3
  61. package/src/components/notification/Notification.tsx +9 -5
  62. package/src/components/popover/Popover.stories.tsx +13 -15
  63. package/src/components/popover/Popover.test.tsx +6 -1
  64. package/src/components/popover/Popover.tsx +6 -6
  65. package/src/components/popover/usePopoverStyle.tsx +1 -3
  66. package/src/components/popover/useRestoreFocusOnClose.tsx +1 -1
  67. package/src/components/popover-dialog/PopoverDialog.tsx +3 -2
  68. package/src/components/post-block/PostBlock.tsx +11 -7
  69. package/src/components/progress/Progress.tsx +3 -3
  70. package/src/components/progress/ProgressCircular.tsx +3 -3
  71. package/src/components/progress/ProgressLinear.tsx +3 -3
  72. package/src/components/progress-tracker/ProgressTracker.stories.tsx +11 -11
  73. package/src/components/progress-tracker/ProgressTracker.tsx +4 -3
  74. package/src/components/progress-tracker/ProgressTrackerStep.tsx +3 -3
  75. package/src/components/progress-tracker/ProgressTrackerStepPanel.tsx +2 -0
  76. package/src/components/radio-button/RadioButton.tsx +3 -3
  77. package/src/components/radio-button/RadioGroup.stories.tsx +1 -4
  78. package/src/components/radio-button/RadioGroup.tsx +3 -2
  79. package/src/components/select/Select.stories.tsx +19 -38
  80. package/src/components/select/Select.tsx +5 -5
  81. package/src/components/select/SelectMultiple.stories.tsx +15 -30
  82. package/src/components/select/SelectMultiple.tsx +3 -4
  83. package/src/components/select/WithSelectContext.tsx +3 -4
  84. package/src/components/select/constants.ts +3 -1
  85. package/src/components/side-navigation/SideNavigation.stories.tsx +1 -1
  86. package/src/components/side-navigation/SideNavigation.tsx +4 -3
  87. package/src/components/side-navigation/SideNavigationItem.tsx +7 -7
  88. package/src/components/skeleton/SkeletonCircle.tsx +3 -3
  89. package/src/components/skeleton/SkeletonRectangle.tsx +3 -3
  90. package/src/components/skeleton/SkeletonTypography.stories.tsx +7 -12
  91. package/src/components/skeleton/SkeletonTypography.tsx +3 -3
  92. package/src/components/slider/Slider.tsx +4 -4
  93. package/src/components/slider/index.ts +1 -1
  94. package/src/components/slideshow/Slides.tsx +6 -4
  95. package/src/components/slideshow/Slideshow.stories.tsx +1 -3
  96. package/src/components/slideshow/Slideshow.tsx +3 -1
  97. package/src/components/slideshow/SlideshowControls.stories.tsx +1 -4
  98. package/src/components/slideshow/SlideshowControls.tsx +4 -4
  99. package/src/components/slideshow/SlideshowItem.tsx +5 -2
  100. package/src/components/slideshow/SlideshowItemGroup.tsx +5 -3
  101. package/src/components/switch/Switch.test.tsx +1 -1
  102. package/src/components/switch/Switch.tsx +7 -4
  103. package/src/components/table/Table.tsx +5 -3
  104. package/src/components/table/TableBody.tsx +7 -3
  105. package/src/components/table/TableCell.tsx +5 -3
  106. package/src/components/table/TableHeader.tsx +7 -3
  107. package/src/components/table/TableRow.tsx +5 -3
  108. package/src/components/tabs/TabList.tsx +1 -1
  109. package/src/components/tabs/TabPanel.tsx +2 -0
  110. package/src/components/tabs/Tabs.stories.tsx +12 -11
  111. package/src/components/text/Text.tsx +14 -5
  112. package/src/components/text-field/TextField.test.tsx +2 -2
  113. package/src/components/text-field/TextField.tsx +8 -7
  114. package/src/components/thumbnail/Thumbnail.tsx +4 -4
  115. package/src/components/toolbar/Toolbar.tsx +3 -3
  116. package/src/components/tooltip/Tooltip.tsx +4 -4
  117. package/src/components/tooltip/context.tsx +1 -1
  118. package/src/components/tooltip/useInjectTooltipRef.tsx +1 -1
  119. package/src/components/uploader/Uploader.tsx +3 -3
  120. package/src/components/user-block/UserBlock.tsx +12 -10
  121. package/src/hooks/useCallbackOnEscape.ts +1 -1
  122. package/src/hooks/useClickAway.tsx +2 -1
  123. package/src/hooks/useFocusTrap.ts +1 -1
  124. package/src/hooks/useInterval.tsx +4 -1
  125. package/src/hooks/useKeyboardListNavigation.tsx +4 -2
  126. package/src/hooks/useSizeOnWindowResize.ts +10 -14
  127. package/src/hooks/useStopPropagation.ts +2 -1
  128. package/src/stories/decorators/withCombinations.tsx +1 -1
  129. package/src/testing/utils/commonTestsSuiteRTL.tsx +2 -2
  130. package/src/utils/ClickAwayProvider/ClickAwayProvider.tsx +4 -0
  131. package/src/utils/className/getRootClassName.test.ts +11 -0
  132. package/src/utils/className/getRootClassName.ts +24 -0
  133. package/src/utils/className/index.ts +1 -0
  134. package/src/utils/date/getMonthCalendar.ts +4 -3
  135. package/src/utils/{makeListenerTowerContext.ts → function/makeListenerTowerContext.ts} +2 -2
  136. package/src/utils/{collection/partitionMulti.ts → partitionMulti.ts} +12 -13
  137. package/src/utils/{flattenChildren.ts → react/flattenChildren.ts} +3 -2
  138. package/src/utils/{renderButtonOrLink.tsx → react/renderButtonOrLink.tsx} +1 -1
  139. package/src/utils/{skipRender.tsx → react/skipRender.tsx} +1 -1
  140. package/src/utils/type/index.ts +18 -18
  141. package/src/utils/type/isComponent.ts +33 -0
  142. package/utils/index.d.ts +4 -0
  143. package/utils/index.js +96 -1
  144. package/utils/index.js.map +1 -1
  145. package/_internal/index.js +0 -99
  146. package/_internal/index.js.map +0 -1
  147. package/src/utils/collection/castArray.test.ts +0 -15
  148. package/src/utils/collection/castArray.ts +0 -3
  149. package/src/utils/collection/chunk.test.ts +0 -15
  150. package/src/utils/collection/chunk.ts +0 -6
  151. package/src/utils/collection/isEmpty.test.js +0 -20
  152. package/src/utils/collection/isEmpty.ts +0 -4
  153. package/src/utils/collection/last.ts +0 -2
  154. package/src/utils/collection/partitionMulti.test.ts +0 -35
  155. package/src/utils/collection/pull.test.ts +0 -17
  156. package/src/utils/collection/pull.ts +0 -7
  157. package/src/utils/collection/range.test.js +0 -9
  158. package/src/utils/collection/range.ts +0 -2
  159. package/src/utils/function/memoize.test.ts +0 -36
  160. package/src/utils/function/memoize.ts +0 -13
  161. package/src/utils/type/ComponentClassName.ts +0 -7
  162. package/src/utils/type/KebabCase.ts +0 -6
  163. /package/src/utils/{clamp.ts → number/clamp.ts} +0 -0
  164. /package/src/utils/{OnBeforeUnmount.tsx → react/OnBeforeUnmount.tsx} +0 -0
  165. /package/src/utils/{mergeRefs.ts → react/mergeRefs.ts} +0 -0
  166. /package/src/utils/{renderLink.tsx → react/renderLink.tsx} +0 -0
@@ -1,4 +1,5 @@
1
- import { Children, Key, ReactChild, ReactNode, cloneElement, isValidElement, ReactElement } from 'react';
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 as ReactElement)?.key ?? index);
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)) {
@@ -1,5 +1,5 @@
1
1
  import React, { ReactElement, ReactNode } from 'react';
2
- import { renderLink } from '@lumx/react/utils/renderLink';
2
+ import { renderLink } from './renderLink';
3
3
 
4
4
  interface Props {
5
5
  linkAs?: any;
@@ -1,5 +1,5 @@
1
1
  import { DOCUMENT } from '@lumx/react/constants';
2
- import { Comp } from '@lumx/react/utils/type';
2
+ import type { Comp } from '@lumx/react/utils/type';
3
3
  import React from 'react';
4
4
 
5
5
  /**
@@ -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
- export { C as ClickAwayProvider } from '../_internal/index.js';
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
@@ -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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"}
@@ -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
@@ -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,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,3 +0,0 @@
1
- /** Cast a value into an array if needed */
2
- export const castArray = <T>(arrayOrElement: T[] | T) =>
3
- Array.isArray(arrayOrElement) ? arrayOrElement : [arrayOrElement];
@@ -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,4 +0,0 @@
1
- import { Falsy } from '../type';
2
-
3
- /** Check if object or array is empty (true on falsy values) */
4
- export const isEmpty = (obj: object | Falsy) => !obj || Object.entries(obj).length === 0;
@@ -1,2 +0,0 @@
1
- /** Get last item from array */
2
- export const last = <T>(array: Array<T>): T | undefined => array[array.length - 1];
@@ -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,7 +0,0 @@
1
- /** Pull an element from an array (inverse of array.push) */
2
- export const pull = <T>(array: Array<T>, element: T) => {
3
- const index = array.indexOf(element);
4
- if (index > -1) {
5
- array.splice(index, 1);
6
- }
7
- };
@@ -1,9 +0,0 @@
1
- import { range } from './range';
2
-
3
- describe(range, () => {
4
- it('should generate a number range', () => {
5
- expect(range(0)).toEqual([]);
6
- expect(range(1)).toEqual([0]);
7
- expect(range(5)).toEqual([0, 1, 2, 3, 4]);
8
- });
9
- });
@@ -1,2 +0,0 @@
1
- /** Generate a range of number starting at 0 and ending before the given number */
2
- export const range = (end: number) => Array.from({ length: end }, (_, i) => i);
@@ -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>}` : ''}`;
@@ -1,6 +0,0 @@
1
- /** Transform a string literal into kebab case */
2
- export type KebabCase<S> = S extends `${infer C}${infer T}`
3
- ? T extends Uncapitalize<T>
4
- ? `${Uncapitalize<C>}${KebabCase<T>}`
5
- : `${Uncapitalize<C>}-${KebabCase<T>}`
6
- : S;
File without changes
File without changes