@lumx/react 3.10.1-alpha.3 → 3.10.1-alpha.4

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 (45) hide show
  1. package/index.js +99 -92
  2. package/index.js.map +1 -1
  3. package/package.json +3 -3
  4. package/src/components/chip/Chip.tsx +1 -1
  5. package/src/components/date-picker/DatePickerControlled.tsx +1 -1
  6. package/src/components/expansion-panel/ExpansionPanel.test.tsx +2 -2
  7. package/src/components/image-lightbox/internal/ImageSlide.tsx +2 -2
  8. package/src/components/image-lightbox/internal/ImageSlideshow.tsx +4 -8
  9. package/src/components/image-lightbox/useImageLightbox.tsx +3 -4
  10. package/src/components/list/ListItem.tsx +1 -1
  11. package/src/components/popover/usePopoverStyle.tsx +3 -1
  12. package/src/components/popover/useRestoreFocusOnClose.tsx +1 -1
  13. package/src/components/popover-dialog/PopoverDialog.test.tsx +1 -1
  14. package/src/components/select/Select.test.tsx +2 -2
  15. package/src/components/slideshow/useSlideFocusManagement.tsx +1 -1
  16. package/src/components/text-field/TextField.test.tsx +2 -2
  17. package/src/components/tooltip/Tooltip.test.tsx +2 -2
  18. package/src/components/tooltip/useTooltipOpen.tsx +3 -3
  19. package/src/hooks/useCallbackOnEscape.ts +1 -1
  20. package/src/hooks/useFocusTrap.ts +1 -1
  21. package/src/hooks/useSizeOnWindowResize.ts +14 -10
  22. package/src/hooks/useTransitionVisibility.ts +2 -2
  23. package/src/utils/{DOM → browser/DOM}/startViewTransition.ts +3 -3
  24. package/src/utils/{focus → browser/focus}/getFirstAndLastFocusable.test.ts +1 -1
  25. package/src/utils/{focus → browser/focus}/getFocusableElements.test.ts +1 -1
  26. package/src/utils/{browserDoesNotSupportHover.test.js → browser/isHoverNotSupported.test.js} +5 -5
  27. package/src/utils/browser/isHoverNotSupported.ts +2 -0
  28. package/src/utils/browser/{getPrefersReducedMotion.ts → isReducedMotion.ts} +1 -1
  29. package/src/utils/className/getFontColorClassName.ts +9 -0
  30. package/src/utils/{className.ts → className/getRootClassName.ts} +1 -21
  31. package/src/utils/className/getTypographyClassName.ts +9 -0
  32. package/src/utils/className/index.ts +4 -0
  33. package/src/utils/function/memoize.test.ts +36 -0
  34. package/src/utils/function/memoize.ts +13 -0
  35. package/src/utils/partitionMulti.test.ts +27 -0
  36. package/src/utils/browserDoesNotSupportHover.ts +0 -2
  37. package/src/utils/isInternetExplorer.ts +0 -15
  38. package/src/utils/userHasReducedMotion.ts +0 -7
  39. package/src/utils/utils.test.ts +0 -21
  40. /package/src/utils/{DOM → browser/DOM}/findImage.tsx +0 -0
  41. /package/src/utils/{event.ts → browser/event.ts} +0 -0
  42. /package/src/utils/{focus → browser/focus}/constants.ts +0 -0
  43. /package/src/utils/{focus → browser/focus}/getFirstAndLastFocusable.ts +0 -0
  44. /package/src/utils/{focus → browser/focus}/getFocusableElements.ts +0 -0
  45. /package/src/utils/{isFocusVisible.ts → browser/isFocusVisible.ts} +0 -0
package/package.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "url": "https://github.com/lumapps/design-system/issues"
7
7
  },
8
8
  "dependencies": {
9
- "@lumx/core": "^3.10.1-alpha.3",
10
- "@lumx/icons": "^3.10.1-alpha.3",
9
+ "@lumx/core": "^3.10.1-alpha.4",
10
+ "@lumx/icons": "^3.10.1-alpha.4",
11
11
  "@popperjs/core": "^2.5.4",
12
12
  "body-scroll-lock": "^3.1.5",
13
13
  "classnames": "^2.3.2",
@@ -110,5 +110,5 @@
110
110
  "build:storybook": "storybook build"
111
111
  },
112
112
  "sideEffects": false,
113
- "version": "3.10.1-alpha.3"
113
+ "version": "3.10.1-alpha.4"
114
114
  }
@@ -7,7 +7,7 @@ import { useStopPropagation } from '@lumx/react/hooks/useStopPropagation';
7
7
 
8
8
  import { GenericProps, HasTheme } from '@lumx/react/utils/type';
9
9
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
10
- import { onEnterPressed } from '@lumx/react/utils/event';
10
+ import { onEnterPressed } from '@lumx/react/utils/browser/event';
11
11
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
12
12
  import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
13
13
 
@@ -21,7 +21,7 @@ import { parseLocale } from '@lumx/react/utils/locale/parseLocale';
21
21
  import { Locale } from '@lumx/react/utils/locale/types';
22
22
  import { usePreviousValue } from '@lumx/react/hooks/usePreviousValue';
23
23
  import { getYearDisplayName } from '@lumx/react/utils/date/getYearDisplayName';
24
- import { onEnterPressed } from '@lumx/react/utils/event';
24
+ import { onEnterPressed } from '@lumx/react/utils/browser/event';
25
25
  import { addMonthResetDay } from '@lumx/react/utils/date/addMonthResetDay';
26
26
  import { formatDayNumber } from '@lumx/react/utils/date/formatDayNumber';
27
27
  import { VISUALLY_HIDDEN } from '@lumx/react/constants';
@@ -4,14 +4,14 @@ import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/uti
4
4
  import { queryByRole, render, screen } from '@testing-library/react';
5
5
  import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
6
6
  import userEvent from '@testing-library/user-event';
7
- import { isFocusVisible } from '@lumx/react/utils/isFocusVisible';
7
+ import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
8
8
 
9
9
  import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
10
10
  import { ExpansionPanel, ExpansionPanelProps } from '.';
11
11
 
12
12
  const CLASSNAME = ExpansionPanel.className as string;
13
13
 
14
- jest.mock('@lumx/react/utils/isFocusVisible');
14
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
15
15
 
16
16
  const mockChildrenContent = 'children content';
17
17
 
@@ -4,7 +4,7 @@ import { SlideshowItem, Thumbnail } from '@lumx/react';
4
4
  import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
5
5
  import { useSizeOnWindowResize } from '@lumx/react/hooks/useSizeOnWindowResize';
6
6
  import { useImageSize } from '@lumx/react/hooks/useImageSize';
7
- import { getPrefersReducedMotion } from '@lumx/react/utils/browser/getPrefersReducedMotion';
7
+ import { isReducedMotion } from '@lumx/react/utils/browser/isReducedMotion';
8
8
  import { isEqual } from '@lumx/react/utils/object/isEqual';
9
9
 
10
10
  import { CLASSNAME } from '../constants';
@@ -97,7 +97,7 @@ export const ImageSlide = React.memo((props: ImageSlideProps) => {
97
97
  maxWidth: scrollAreaSize?.width,
98
98
  }),
99
99
  // Only animate when scale is set, and we are not pointer zooming and the user does not prefer reduced motion
100
- transition: scale && !isPointerZooming && !getPrefersReducedMotion() ? 'all 250ms' : undefined,
100
+ transition: scale && !isPointerZooming && !isReducedMotion() ? 'all 250ms' : undefined,
101
101
  },
102
102
  }}
103
103
  loadingPlaceholderImageRef={loadingPlaceholderImageRef}
@@ -3,8 +3,8 @@ import React from 'react';
3
3
  import { mdiMagnifyMinusOutline, mdiMagnifyPlusOutline } from '@lumx/icons';
4
4
  import { FlexBox, IconButton, Slides, SlideshowControls } from '@lumx/react';
5
5
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
6
+ import { memoize } from '@lumx/react/utils/function/memoize';
6
7
 
7
- import memoize from 'lodash/memoize';
8
8
  import { ImageCaption } from '../../image-block/ImageCaption';
9
9
  import { CLASSNAME } from '../constants';
10
10
  import type { ImagesProps, InheritedSlideShowProps, ZoomButtonProps } from '../types';
@@ -113,13 +113,9 @@ export const ImageSlideshow: React.FC<ImageSlideshowProps> = ({
113
113
 
114
114
  const getImgRef = React.useMemo(
115
115
  () =>
116
- memoize(
117
- (index: number, isActive: boolean) => {
118
- return mergeRefs(images?.[index].imgRef, isActive ? activeImageRef : undefined);
119
- },
120
- // memoize based on both arguments
121
- (...args) => args.join(),
122
- ),
116
+ memoize((index: number, isActive: boolean) => {
117
+ return mergeRefs(images?.[index].imgRef, isActive ? activeImageRef : undefined);
118
+ }),
123
119
  [images, activeImageRef],
124
120
  );
125
121
 
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
2
 
3
- import memoize from 'lodash/memoize';
4
-
5
- import { startViewTransition } from '@lumx/react/utils/DOM/startViewTransition';
6
- import { findImage } from '@lumx/react/utils/DOM/findImage';
3
+ import { startViewTransition } from '@lumx/react/utils/browser/DOM/startViewTransition';
4
+ import { findImage } from '@lumx/react/utils/browser/DOM/findImage';
5
+ import { memoize } from '@lumx/react/utils/function/memoize';
7
6
 
8
7
  import type { ImageLightboxProps } from './types';
9
8
  import { CLASSNAME } from './constants';
@@ -4,7 +4,7 @@ import classNames from 'classnames';
4
4
 
5
5
  import { ListProps, Size } from '@lumx/react';
6
6
  import { GenericProps } from '@lumx/react/utils/type';
7
- import { onEnterPressed, onButtonPressed } from '@lumx/react/utils/event';
7
+ import { onEnterPressed, onButtonPressed } from '@lumx/react/utils/browser/event';
8
8
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
9
9
  import { renderLink } from '@lumx/react/utils/renderLink';
10
10
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
@@ -1,10 +1,12 @@
1
1
  import React, { useEffect, useMemo, useState } from 'react';
2
- import memoize from 'lodash/memoize';
2
+
3
3
  import { detectOverflow } from '@popperjs/core';
4
4
 
5
5
  import { DOCUMENT, WINDOW } from '@lumx/react/constants';
6
6
  import { PopoverProps } from '@lumx/react/components/popover/Popover';
7
7
  import { usePopper } from '@lumx/react/hooks/usePopper';
8
+ import { memoize } from '@lumx/react/utils/function/memoize';
9
+
8
10
  import { ARROW_SIZE, FitAnchorWidth, Placement } from './constants';
9
11
 
10
12
  /**
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';
2
+ import { getFirstAndLastFocusable } from '@lumx/react/utils/browser/focus/getFirstAndLastFocusable';
3
3
  import { OnBeforeUnmount } from '@lumx/react/utils/OnBeforeUnmount';
4
4
  import type { PopoverProps } from './Popover';
5
5
 
@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
5
5
  import { PopoverDialog } from './PopoverDialog';
6
6
  import { WithButtonTrigger, WithIconButtonTrigger } from './PopoverDialog.stories';
7
7
 
8
- jest.mock('@lumx/react/utils/isFocusVisible');
8
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
9
9
 
10
10
  describe(`<${PopoverDialog.displayName}>`, () => {
11
11
  it('should open and init focus', async () => {
@@ -7,13 +7,13 @@ import { getByClassName, queryAllByClassName, queryByClassName } from '@lumx/rea
7
7
  import { render, within } from '@testing-library/react';
8
8
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
9
9
  import userEvent from '@testing-library/user-event';
10
- import { isFocusVisible } from '@lumx/react/utils/isFocusVisible';
10
+ import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
11
11
 
12
12
  import { Select, SelectProps, SelectVariant } from './Select';
13
13
 
14
14
  const CLASSNAME = Select.className as string;
15
15
 
16
- jest.mock('@lumx/react/utils/isFocusVisible');
16
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
17
17
  jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
18
18
 
19
19
  /**
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect } from 'react';
2
- import { getFocusableElements } from '@lumx/react/utils/focus/getFocusableElements';
2
+ import { getFocusableElements } from '@lumx/react/utils/browser/focus/getFocusableElements';
3
3
 
4
4
  export interface UseSlideFocusManagementProps {
5
5
  isSlideDisplayed?: boolean;
@@ -14,13 +14,13 @@ import {
14
14
  } from '@lumx/react/testing/utils/queries';
15
15
  import userEvent from '@testing-library/user-event';
16
16
 
17
- import { isFocusVisible } from '@lumx/react/utils/isFocusVisible';
17
+ import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
18
18
  import { partitionMulti } from '@lumx/react/utils/collection/partitionMulti';
19
19
  import { TextField, TextFieldProps } from './TextField';
20
20
 
21
21
  const CLASSNAME = TextField.className as string;
22
22
 
23
- jest.mock('@lumx/react/utils/isFocusVisible');
23
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
24
24
 
25
25
  /**
26
26
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -5,14 +5,14 @@ import { screen, render } from '@testing-library/react';
5
5
  import { queryAllByTagName, queryByClassName } from '@lumx/react/testing/utils/queries';
6
6
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
7
7
  import userEvent from '@testing-library/user-event';
8
- import { isFocusVisible } from '@lumx/react/utils/isFocusVisible';
8
+ import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
9
9
  import { VISUALLY_HIDDEN } from '@lumx/react/constants';
10
10
 
11
11
  import { Tooltip, TooltipProps } from './Tooltip';
12
12
 
13
13
  const CLASSNAME = Tooltip.className as string;
14
14
 
15
- jest.mock('@lumx/react/utils/isFocusVisible');
15
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
16
16
  jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
17
17
  // Skip delays
18
18
  jest.mock('@lumx/react/constants', () => ({
@@ -1,8 +1,8 @@
1
1
  import { MutableRefObject, useEffect, useRef, useState } from 'react';
2
- import { browserDoesNotSupportHover } from '@lumx/react/utils/browserDoesNotSupportHover';
2
+ import { isHoverNotSupported } from '@lumx/react/utils/browser/isHoverNotSupported';
3
3
  import { IS_BROWSER, TOOLTIP_HOVER_DELAY, TOOLTIP_LONG_PRESS_DELAY } from '@lumx/react/constants';
4
4
  import { useCallbackOnEscape } from '@lumx/react/hooks/useCallbackOnEscape';
5
- import { isFocusVisible } from '@lumx/react/utils/isFocusVisible';
5
+ import { isFocusVisible } from '@lumx/react/utils/browser/isFocusVisible';
6
6
 
7
7
  /**
8
8
  * Hook controlling tooltip visibility using mouse hover the anchor and delay.
@@ -39,7 +39,7 @@ export function useTooltipOpen(delay: number | undefined, anchorElement: HTMLEle
39
39
  else timer = setTimeout(update, duration) as any;
40
40
  };
41
41
 
42
- const hoverNotSupported = browserDoesNotSupportHover();
42
+ const hoverNotSupported = isHoverNotSupported();
43
43
  const hasTouch = 'ontouchstart' in window;
44
44
 
45
45
  // Adapt open/close delay
@@ -1,6 +1,6 @@
1
1
  import { DOCUMENT } from '@lumx/react/constants';
2
2
  import { Callback } from '@lumx/react/utils/type';
3
- import { onEscapePressed } from '@lumx/react/utils/event';
3
+ import { onEscapePressed } from '@lumx/react/utils/browser/event';
4
4
  import { useEffect } from 'react';
5
5
  import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
6
6
 
@@ -1,7 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
 
3
3
  import { DOCUMENT } from '@lumx/react/constants';
4
- import { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';
4
+ import { getFirstAndLastFocusable } from '@lumx/react/utils/browser/focus/getFirstAndLastFocusable';
5
5
  import { Falsy } from '@lumx/react/utils/type';
6
6
  import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
7
7
 
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
 
3
- import throttle from 'lodash/throttle';
4
- import { RectSize } from '@lumx/react/utils/type';
3
+ import type { RectSize } from '@lumx/react/utils/type';
5
4
 
6
5
  /**
7
6
  * Observe element size (only works if it's size depends on the window size).
@@ -13,14 +12,19 @@ import { RectSize } from '@lumx/react/utils/type';
13
12
  */
14
13
  export function useSizeOnWindowResize(elementRef: React.RefObject<HTMLElement>): [RectSize | null, () => void] {
15
14
  const [size, setSize] = React.useState<null | RectSize>(null);
16
- const updateSize = React.useMemo(
17
- () =>
18
- throttle(() => {
19
- const newSize = elementRef.current?.getBoundingClientRect();
20
- if (newSize) setSize(newSize);
21
- }, 10),
22
- [elementRef],
23
- );
15
+ const updateSize = React.useMemo(() => {
16
+ let prevTimeout: ReturnType<typeof setTimeout> | undefined;
17
+ function update() {
18
+ const newSize = elementRef.current?.getBoundingClientRect();
19
+ if (newSize) setSize(newSize);
20
+ prevTimeout = undefined;
21
+ }
22
+ return () => {
23
+ if (!prevTimeout) {
24
+ prevTimeout = setTimeout(update, 10);
25
+ }
26
+ };
27
+ }, [elementRef]);
24
28
  React.useEffect(() => {
25
29
  updateSize();
26
30
  window.addEventListener('resize', updateSize);
@@ -1,5 +1,5 @@
1
1
  import { RefObject, useEffect, useRef, useState } from 'react';
2
- import { userHasReducedMotion } from '@lumx/react/utils/userHasReducedMotion';
2
+ import { isReducedMotion } from '@lumx/react/utils/browser/isReducedMotion';
3
3
 
4
4
  /**
5
5
  * Returns true if the component is visible tracking the opacity transition.
@@ -28,7 +28,7 @@ export const useTransitionVisibility = (
28
28
 
29
29
  // Transition event is not supported or the user prefers reduced motion.
30
30
  // => Skip and set visibility to false directly.
31
- if (!element || !window.TransitionEvent || userHasReducedMotion()) {
31
+ if (!element || !window.TransitionEvent || isReducedMotion()) {
32
32
  setVisible(false);
33
33
  return undefined;
34
34
  }
@@ -2,8 +2,8 @@ import ReactDOM from 'react-dom';
2
2
 
3
3
  import { MaybeElementOrRef } from '@lumx/react/utils/type';
4
4
 
5
- import { unref } from '../react/unref';
6
- import { getPrefersReducedMotion } from '../browser/getPrefersReducedMotion';
5
+ import { unref } from '../../react/unref';
6
+ import { isReducedMotion } from '../isReducedMotion';
7
7
 
8
8
  function setupViewTransitionName(elementRef: MaybeElementOrRef<HTMLElement>, name: string) {
9
9
  let originalName: string | null = null;
@@ -41,7 +41,7 @@ export async function startViewTransition({
41
41
  };
42
42
  }) {
43
43
  const start = (document as any)?.startViewTransition?.bind(document);
44
- const prefersReducedMotion = getPrefersReducedMotion();
44
+ const prefersReducedMotion = isReducedMotion();
45
45
  const { flushSync } = ReactDOM as any;
46
46
  if (prefersReducedMotion || !start || !flushSync || !viewTransitionName?.source || !viewTransitionName?.target) {
47
47
  // Skip, apply changes without a transition
@@ -1,4 +1,4 @@
1
- import { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';
1
+ import { getFirstAndLastFocusable } from './getFirstAndLastFocusable';
2
2
 
3
3
  function htmlToElement(html: string): any {
4
4
  const template = document.createElement('template');
@@ -1,4 +1,4 @@
1
- import { getFocusableElements } from '@lumx/react/utils/focus/getFocusableElements';
1
+ import { getFocusableElements } from './getFocusableElements';
2
2
 
3
3
  function htmlToElement(html: string): any {
4
4
  const template = document.createElement('template');
@@ -1,24 +1,24 @@
1
- import { browserDoesNotSupportHover } from '@lumx/react/utils/browserDoesNotSupportHover';
1
+ import { isHoverNotSupported } from './isHoverNotSupported';
2
2
 
3
3
  const originalMatchMedia = global.matchMedia;
4
4
 
5
- describe('browserDoesNotSupportHover', () => {
5
+ describe('isHoverNotSupported', () => {
6
6
  afterAll(() => {
7
7
  global.matchMedia = originalMatchMedia;
8
8
  });
9
9
 
10
10
  it('should return `false` on browsers that do not support matchMedia', () => {
11
11
  global.matchMedia = undefined;
12
- expect(browserDoesNotSupportHover()).toBe(false);
12
+ expect(isHoverNotSupported()).toBe(false);
13
13
  });
14
14
 
15
15
  it('should return `false` on browsers that support matchMedia and does support hover', () => {
16
16
  global.matchMedia = () => ({ matches: false });
17
- expect(browserDoesNotSupportHover()).toBe(false);
17
+ expect(isHoverNotSupported()).toBe(false);
18
18
  });
19
19
 
20
20
  it('should return `true` on browsers that support matchMedia and does not support hover', () => {
21
21
  global.matchMedia = () => ({ matches: true });
22
- expect(browserDoesNotSupportHover()).toBe(true);
22
+ expect(isHoverNotSupported()).toBe(true);
23
23
  });
24
24
  });
@@ -0,0 +1,2 @@
1
+ /** Return true if the browser does not support pointer hover */
2
+ export const isHoverNotSupported = (): boolean => !!window.matchMedia?.('(hover: none)').matches;
@@ -1,6 +1,6 @@
1
1
  import { WINDOW } from '@lumx/react/constants';
2
2
 
3
3
  /** Check if user prefers reduced motion */
4
- export function getPrefersReducedMotion() {
4
+ export function isReducedMotion() {
5
5
  return WINDOW?.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
6
6
  }
@@ -0,0 +1,9 @@
1
+ import { ColorPalette, ColorVariant } from '@lumx/react';
2
+
3
+ /**
4
+ * Returns the classname associated to the given color and variant.
5
+ * For example, for 'dark' and 'L2' it returns `lumx-color-font-dark-l2`
6
+ */
7
+ export const getFontColorClassName = (color: ColorPalette, colorVariant: ColorVariant = ColorVariant.N) => {
8
+ return `lumx-color-font-${color}-${colorVariant}`;
9
+ };
@@ -1,13 +1,9 @@
1
- import { CSS_PREFIX } from '@lumx/react/constants';
2
-
1
+ import { CSS_PREFIX } from '@lumx/core/js/constants';
3
2
  import kebabCase from 'lodash/kebabCase';
4
- import { ColorPalette, ColorVariant, Typography } from '@lumx/react/components';
5
3
 
6
4
  // See https://regex101.com/r/YjS1uI/3
7
5
  const LAST_PART_CLASSNAME = /^(.*)-(.+)$/gi;
8
6
 
9
- export { getBasicClass, handleBasicClasses } from '@lumx/core/js/utils';
10
-
11
7
  /**
12
8
  * Get the name of the root CSS class of a component based on its name.
13
9
  *
@@ -26,19 +22,3 @@ export function getRootClassName(componentName: string, subComponent?: boolean):
26
22
  }
27
23
  return formattedClassName;
28
24
  }
29
-
30
- /**
31
- * Returns the classname associated to the given color and variant.
32
- * For example, for 'dark' and 'L2' it returns `lumx-color-font-dark-l2`
33
- */
34
- export const getFontColorClassName = (color: ColorPalette, colorVariant: ColorVariant = ColorVariant.N) => {
35
- return `lumx-color-font-${color}-${colorVariant}`;
36
- };
37
-
38
- /**
39
- * Returns the classname associated to the given typography.
40
- * For example, for `Typography.title` it returns `lumx-typography-title`
41
- */
42
- export const getTypographyClassName = (typography: Typography) => {
43
- return `lumx-typography-${typography}`;
44
- };
@@ -0,0 +1,9 @@
1
+ import { Typography } from '@lumx/react';
2
+
3
+ /**
4
+ * Returns the classname associated to the given typography.
5
+ * For example, for `Typography.title` it returns `lumx-typography-title`
6
+ */
7
+ export const getTypographyClassName = (typography: Typography) => {
8
+ return `lumx-typography-${typography}`;
9
+ };
@@ -0,0 +1,4 @@
1
+ export { getBasicClass, handleBasicClasses } from '@lumx/core/js/utils';
2
+ export { getRootClassName } from './getRootClassName';
3
+ export { getTypographyClassName } from './getTypographyClassName';
4
+ export { getFontColorClassName } from './getFontColorClassName';
@@ -0,0 +1,36 @@
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
+ });
@@ -0,0 +1,13 @@
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
+ }
@@ -0,0 +1,27 @@
1
+ import partition from 'lodash/partition';
2
+ import { partitionMulti } from './partitionMulti';
3
+
4
+ describe('partitionMulti', () => {
5
+ it('should act like partition for single predicate', () => {
6
+ const data = [0, 1, 2, 3, 4, 5];
7
+ const isEven = (n: number): boolean => n % 2 === 0;
8
+
9
+ const expected = partition(data, isEven);
10
+ const actual = partitionMulti(data, [isEven]);
11
+
12
+ expect(actual).toEqual(expected);
13
+ });
14
+
15
+ it('should partition on multiple predicates', () => {
16
+ type T = string | number | boolean;
17
+ const data: T[] = ['a', 1, 'b', false, true];
18
+ const isString = (s: T): boolean => typeof s === 'string';
19
+ const isNumber = (s: T): boolean => typeof s === 'number';
20
+
21
+ const [strings, numbers, others] = partitionMulti(data, [isString, isNumber]);
22
+
23
+ expect(strings).toEqual(['a', 'b']);
24
+ expect(numbers).toEqual([1]);
25
+ expect(others).toEqual([false, true]);
26
+ });
27
+ });
@@ -1,2 +0,0 @@
1
- /** Return true if the browser does not support pointer hover */
2
- export const browserDoesNotSupportHover = (): boolean => !!window.matchMedia?.('(hover: none)').matches;
@@ -1,15 +0,0 @@
1
- import { WINDOW } from '@lumx/react/constants';
2
-
3
- /**
4
- * Check if browser is IE
5
- * @return Browser is IE or not
6
- */
7
- export const isInternetExplorer = () => {
8
- const userAgent = WINDOW?.navigator?.userAgent;
9
- if (!userAgent) {
10
- return false;
11
- }
12
- const msie = userAgent.indexOf('MSIE ');
13
- const isIEVersion = !!userAgent.match(/Trident.*rv:11\./);
14
- return msie > 0 || isIEVersion;
15
- };
@@ -1,7 +0,0 @@
1
- export const userHasReducedMotion = () => {
2
- try {
3
- return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4
- } catch (e) {
5
- return false;
6
- }
7
- };
@@ -1,21 +0,0 @@
1
- import { isInternetExplorer } from './isInternetExplorer';
2
-
3
- describe('isInternetExplorer', () => {
4
- it('should detect IE 10', () => {
5
- const userAgentIE10 = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)';
6
- Object.defineProperty(window.navigator, 'userAgent', { value: userAgentIE10, configurable: true });
7
- expect(isInternetExplorer()).toEqual(true);
8
- });
9
-
10
- it('should detect IE 11', () => {
11
- const userAgentIE11 = 'Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko';
12
- Object.defineProperty(window.navigator, 'userAgent', { value: userAgentIE11, configurable: true });
13
- expect(isInternetExplorer()).toEqual(true);
14
- });
15
-
16
- it('should not detect IE', () => {
17
- const userAgentFirefox = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0';
18
- Object.defineProperty(window.navigator, 'userAgent', { value: userAgentFirefox, configurable: true });
19
- expect(isInternetExplorer()).toEqual(false);
20
- });
21
- });
File without changes
File without changes
File without changes