@lumx/react 2.2.2 → 2.2.3-alpha-export-hook1

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 (195) hide show
  1. package/esm/_internal/AlertDialog.js +1 -1
  2. package/esm/_internal/AutocompleteMultiple.js.map +1 -1
  3. package/esm/_internal/ButtonGroup.js +0 -4
  4. package/esm/_internal/ButtonGroup.js.map +1 -1
  5. package/esm/_internal/Checkbox2.js +6 -4
  6. package/esm/_internal/Checkbox2.js.map +1 -1
  7. package/esm/_internal/Chip2.js +2 -1
  8. package/esm/_internal/Chip2.js.map +1 -1
  9. package/esm/_internal/ChipGroup.js.map +1 -1
  10. package/esm/_internal/ClickAwayProvider.js +1 -1
  11. package/esm/_internal/ClickAwayProvider.js.map +1 -1
  12. package/esm/_internal/DatePickerField.js +0 -4
  13. package/esm/_internal/DatePickerField.js.map +1 -1
  14. package/esm/_internal/Dialog2.js.map +1 -1
  15. package/esm/_internal/Dropdown2.js +1 -1
  16. package/esm/_internal/Dropdown2.js.map +1 -1
  17. package/esm/_internal/IconButton.js +0 -4
  18. package/esm/_internal/IconButton.js.map +1 -1
  19. package/esm/_internal/Lightbox2.js.map +1 -1
  20. package/esm/_internal/List2.js +20 -4
  21. package/esm/_internal/List2.js.map +1 -1
  22. package/esm/_internal/Notification2.js.map +1 -1
  23. package/esm/_internal/Popover2.js.map +1 -1
  24. package/esm/_internal/ProgressTrackerStepPanel.js.map +1 -1
  25. package/esm/_internal/RadioGroup.js +1 -1
  26. package/esm/_internal/SelectMultiple.js +1 -1
  27. package/esm/_internal/SelectMultiple.js.map +1 -1
  28. package/esm/_internal/SideNavigationItem.js +2 -1
  29. package/esm/_internal/SideNavigationItem.js.map +1 -1
  30. package/esm/_internal/Slider2.js +1 -1
  31. package/esm/_internal/Slider2.js.map +1 -1
  32. package/esm/_internal/SlideshowControls.js +100 -2
  33. package/esm/_internal/SlideshowControls.js.map +1 -1
  34. package/esm/_internal/Switch2.js +6 -4
  35. package/esm/_internal/Switch2.js.map +1 -1
  36. package/esm/_internal/TabPanel.js.map +1 -1
  37. package/esm/_internal/TableRow.js +2 -1
  38. package/esm/_internal/TableRow.js.map +1 -1
  39. package/esm/_internal/TextField.js +1 -1
  40. package/esm/_internal/Tooltip2.js +12 -145
  41. package/esm/_internal/Tooltip2.js.map +1 -1
  42. package/esm/_internal/alert-dialog.js +3 -3
  43. package/esm/_internal/autocomplete.js +6 -5
  44. package/esm/_internal/autocomplete.js.map +1 -1
  45. package/esm/_internal/avatar.js +1 -2
  46. package/esm/_internal/avatar.js.map +1 -1
  47. package/esm/_internal/badge.js +1 -2
  48. package/esm/_internal/badge.js.map +1 -1
  49. package/esm/_internal/button.js +4 -4
  50. package/esm/_internal/checkbox.js +2 -3
  51. package/esm/_internal/checkbox.js.map +1 -1
  52. package/esm/_internal/chip.js +2 -2
  53. package/esm/_internal/comment-block.js +1 -2
  54. package/esm/_internal/comment-block.js.map +1 -1
  55. package/esm/_internal/constants.js.map +1 -1
  56. package/esm/_internal/date-picker.js +4 -4
  57. package/esm/_internal/dialog.js +2 -2
  58. package/esm/_internal/divider.js +1 -2
  59. package/esm/_internal/divider.js.map +1 -1
  60. package/esm/_internal/drag-handle.js +1 -2
  61. package/esm/_internal/drag-handle.js.map +1 -1
  62. package/esm/_internal/dropdown.js +4 -3
  63. package/esm/_internal/dropdown.js.map +1 -1
  64. package/esm/_internal/expansion-panel.js +4 -4
  65. package/esm/_internal/flag.js +1 -2
  66. package/esm/_internal/flag.js.map +1 -1
  67. package/esm/_internal/flex-box.js +1 -2
  68. package/esm/_internal/flex-box.js.map +1 -1
  69. package/esm/_internal/getRootClassName.js +40 -166
  70. package/esm/_internal/getRootClassName.js.map +1 -1
  71. package/esm/_internal/grid.js +1 -2
  72. package/esm/_internal/grid.js.map +1 -1
  73. package/esm/_internal/icon.js +1 -2
  74. package/esm/_internal/icon.js.map +1 -1
  75. package/esm/_internal/image-block.js +1 -2
  76. package/esm/_internal/image-block.js.map +1 -1
  77. package/esm/{index2.js → _internal/index.js} +1 -1
  78. package/esm/_internal/index.js.map +1 -0
  79. package/esm/_internal/input-helper.js +1 -2
  80. package/esm/_internal/input-helper.js.map +1 -1
  81. package/esm/_internal/input-label.js +1 -2
  82. package/esm/_internal/input-label.js.map +1 -1
  83. package/esm/_internal/lightbox.js +4 -4
  84. package/esm/_internal/link-preview.js +1 -2
  85. package/esm/_internal/link-preview.js.map +1 -1
  86. package/esm/_internal/link.js +1 -2
  87. package/esm/_internal/link.js.map +1 -1
  88. package/esm/_internal/list.js +3 -3
  89. package/esm/_internal/message.js +1 -2
  90. package/esm/_internal/message.js.map +1 -1
  91. package/esm/_internal/mosaic.js +1 -2
  92. package/esm/_internal/mosaic.js.map +1 -1
  93. package/esm/_internal/notification.js +1 -2
  94. package/esm/_internal/notification.js.map +1 -1
  95. package/esm/_internal/onEnterPressed.js +20 -0
  96. package/esm/_internal/onEnterPressed.js.map +1 -0
  97. package/esm/_internal/onEscapePressed.js +20 -0
  98. package/esm/_internal/onEscapePressed.js.map +1 -0
  99. package/esm/_internal/popover.js +2 -2
  100. package/esm/_internal/post-block.js +1 -2
  101. package/esm/_internal/post-block.js.map +1 -1
  102. package/esm/_internal/progress-tracker.js +2 -3
  103. package/esm/_internal/progress-tracker.js.map +1 -1
  104. package/esm/_internal/progress.js +1 -2
  105. package/esm/_internal/progress.js.map +1 -1
  106. package/esm/_internal/radio-button.js +2 -3
  107. package/esm/_internal/radio-button.js.map +1 -1
  108. package/esm/_internal/select.js +6 -5
  109. package/esm/_internal/select.js.map +1 -1
  110. package/esm/_internal/side-navigation.js +5 -4
  111. package/esm/_internal/side-navigation.js.map +1 -1
  112. package/esm/_internal/skeleton.js +1 -2
  113. package/esm/_internal/skeleton.js.map +1 -1
  114. package/esm/_internal/slider.js +2 -3
  115. package/esm/_internal/slider.js.map +1 -1
  116. package/esm/_internal/slideshow.js +6 -5
  117. package/esm/_internal/slideshow.js.map +1 -1
  118. package/esm/_internal/switch.js +2 -3
  119. package/esm/_internal/switch.js.map +1 -1
  120. package/esm/_internal/table.js +2 -2
  121. package/esm/_internal/tabs.js +2 -3
  122. package/esm/_internal/tabs.js.map +1 -1
  123. package/esm/_internal/text-field.js +4 -4
  124. package/esm/_internal/thumbnail.js +1 -2
  125. package/esm/_internal/thumbnail.js.map +1 -1
  126. package/esm/_internal/toolbar.js +1 -2
  127. package/esm/_internal/toolbar.js.map +1 -1
  128. package/esm/_internal/tooltip.js +4 -4
  129. package/esm/_internal/uploader.js +1 -2
  130. package/esm/_internal/uploader.js.map +1 -1
  131. package/esm/_internal/useDelayedVisibility.js.map +1 -1
  132. package/esm/_internal/useDisableBodyScroll.js.map +1 -1
  133. package/esm/_internal/useFocusTrap.js.map +1 -1
  134. package/esm/_internal/useRovingTabIndex.js +1 -1
  135. package/esm/_internal/useRovingTabIndex.js.map +1 -1
  136. package/esm/_internal/user-block.js +1 -2
  137. package/esm/_internal/user-block.js.map +1 -1
  138. package/esm/hooks/useOpenHoverOrLongPress.js +172 -0
  139. package/esm/hooks/useOpenHoverOrLongPress.js.map +1 -0
  140. package/esm/index.js +8 -6
  141. package/esm/index.js.map +1 -1
  142. package/package.json +4 -4
  143. package/src/{hooks → _internal/hooks}/useBooleanState.tsx +0 -0
  144. package/src/{hooks → _internal/hooks}/useCallbackOnEscape.ts +0 -0
  145. package/src/{hooks → _internal/hooks}/useChipGroupNavigation.tsx +0 -0
  146. package/src/{hooks → _internal/hooks}/useClickAway.tsx +0 -0
  147. package/src/{hooks → _internal/hooks}/useDelayedVisibility.tsx +0 -0
  148. package/src/{hooks → _internal/hooks}/useDisableBodyScroll.ts +0 -0
  149. package/src/{hooks → _internal/hooks}/useEventCallback.tsx +0 -0
  150. package/src/{hooks → _internal/hooks}/useFocus.tsx +0 -0
  151. package/src/{hooks → _internal/hooks}/useFocusTrap.ts +0 -0
  152. package/src/{hooks → _internal/hooks}/useInfiniteScroll.tsx +0 -0
  153. package/src/{hooks → _internal/hooks}/useIntersectionObserver.tsx +0 -0
  154. package/src/{hooks → _internal/hooks}/useInterval.tsx +1 -1
  155. package/src/{hooks → _internal/hooks}/useKeyboardListNavigation.tsx +0 -0
  156. package/src/{hooks → _internal/hooks}/useListenFocus.tsx +0 -0
  157. package/src/{hooks → _internal/hooks}/useOnResize.ts +0 -0
  158. package/src/{hooks → _internal/hooks}/useRovingTabIndex.tsx +0 -0
  159. package/src/{hooks → _internal/hooks}/useStopPropagation.ts +0 -0
  160. package/src/components/autocomplete/Autocomplete.tsx +1 -1
  161. package/src/components/button/__snapshots__/IconButton.test.tsx.snap +0 -5
  162. package/src/components/checkbox/Checkbox.test.tsx +14 -0
  163. package/src/components/checkbox/Checkbox.tsx +5 -1
  164. package/src/components/checkbox/__snapshots__/Checkbox.test.tsx.snap +51 -0
  165. package/src/components/chip/Chip.tsx +1 -1
  166. package/src/components/chip/ChipGroup.tsx +1 -1
  167. package/src/components/date-picker/DatePickerField.tsx +2 -2
  168. package/src/components/dialog/Dialog.test.tsx +1 -1
  169. package/src/components/dialog/Dialog.tsx +5 -5
  170. package/src/components/dropdown/Dropdown.tsx +1 -1
  171. package/src/components/lightbox/Lightbox.tsx +4 -4
  172. package/src/components/list/List.tsx +1 -1
  173. package/src/components/mosaic/Mosaic.test.tsx +1 -1
  174. package/src/components/notification/Notification.tsx +1 -1
  175. package/src/components/popover/Popover.tsx +2 -2
  176. package/src/components/progress-tracker/ProgressTracker.tsx +1 -1
  177. package/src/components/select/Select.stories.tsx +1 -1
  178. package/src/components/select/SelectMultiple.stories.tsx +1 -1
  179. package/src/components/select/WithSelectContext.tsx +1 -1
  180. package/src/components/slider/Slider.tsx +1 -1
  181. package/src/components/slideshow/Slideshow.tsx +1 -1
  182. package/src/components/slideshow/useSwipeNavigate.ts +1 -1
  183. package/src/components/switch/Switch.test.tsx +10 -0
  184. package/src/components/switch/Switch.tsx +5 -1
  185. package/src/components/switch/__snapshots__/Switch.test.tsx.snap +30 -0
  186. package/src/components/tabs/TabList.tsx +4 -4
  187. package/src/components/tooltip/Tooltip.tsx +7 -4
  188. package/src/constants.ts +7 -1
  189. package/src/hooks/useOpenHoverOrLongPress.ts +140 -0
  190. package/src/utils/ClickAwayProvider/ClickAwayProvider.tsx +1 -1
  191. package/src/utils/browserDoesNotSupportHover.test.js +24 -0
  192. package/src/utils/browserDoesNotSupportHover.ts +2 -0
  193. package/types.d.ts +6 -2
  194. package/esm/index2.js.map +0 -1
  195. package/src/components/tooltip/useTooltipOpen.tsx +0 -112
@@ -10,7 +10,7 @@ import { Placement } from '@lumx/react/components/popover/Popover';
10
10
 
11
11
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils';
12
12
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
13
- import { useListenFocus } from '@lumx/react/hooks/useListenFocus';
13
+ import { useListenFocus } from '@lumx/react/_internal/hooks/useListenFocus';
14
14
  import { CoreSelectProps, SelectVariant } from './constants';
15
15
 
16
16
  /** The display name of the component. */
@@ -5,7 +5,7 @@ import classNames from 'classnames';
5
5
 
6
6
  import { InputHelper, InputLabel, Theme } from '@lumx/react';
7
7
 
8
- import useEventCallback from '@lumx/react/hooks/useEventCallback';
8
+ import useEventCallback from '@lumx/react/_internal/hooks/useEventCallback';
9
9
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
10
10
 
11
11
  import { uid } from 'uid';
@@ -5,7 +5,7 @@ import classNames from 'classnames';
5
5
  import { SlideshowControls, SlideshowControlsProps, Theme } from '@lumx/react';
6
6
 
7
7
  import { AUTOPLAY_DEFAULT_INTERVAL, FULL_WIDTH_PERCENT } from '@lumx/react/components/slideshow/constants';
8
- import { useInterval } from '@lumx/react/hooks/useInterval';
8
+ import { useInterval } from '@lumx/react/_internal/hooks/useInterval';
9
9
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
10
10
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
11
11
 
@@ -1,5 +1,5 @@
1
1
  import { useEffect } from 'react';
2
- import { detectHorizontalSwipe } from '@lumx/core/js/utils';
2
+ import { detectHorizontalSwipe } from '@lumx/core/js/utils/detectHorizontalSwipe';
3
3
 
4
4
  const isTouchDevice = () => 'ontouchstart' in window;
5
5
 
@@ -142,6 +142,16 @@ describe(`<${Switch.displayName}>`, () => {
142
142
  }
143
143
  });
144
144
  });
145
+
146
+ it('should use the given props while passing custom props to input', () => {
147
+ const { wrapper } = setup({
148
+ inputProps: {
149
+ 'aria-labelledby': 'labelledby-id',
150
+ },
151
+ });
152
+
153
+ expect(wrapper).toMatchSnapshot();
154
+ });
145
155
  });
146
156
 
147
157
  // 3. Test events.
@@ -1,4 +1,4 @@
1
- import React, { Children, forwardRef, SyntheticEvent, useMemo } from 'react';
1
+ import React, { Children, forwardRef, InputHTMLAttributes, SyntheticEvent, useMemo } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import { uid } from 'uid';
@@ -29,6 +29,8 @@ export interface SwitchProps extends GenericProps {
29
29
  value?: string;
30
30
  /** On change callback. */
31
31
  onChange?(isChecked: boolean, value?: string, name?: string, event?: SyntheticEvent): void;
32
+ /** optional props for input */
33
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
32
34
  }
33
35
 
34
36
  /**
@@ -71,6 +73,7 @@ export const Switch: Comp<SwitchProps, HTMLDivElement> = forwardRef((props, ref)
71
73
  position,
72
74
  theme,
73
75
  value,
76
+ inputProps = {},
74
77
  ...forwardedProps
75
78
  } = props;
76
79
  const switchId = useMemo(() => id || `switch-${uid()}`, [id]);
@@ -109,6 +112,7 @@ export const Switch: Comp<SwitchProps, HTMLDivElement> = forwardRef((props, ref)
109
112
  checked={isChecked}
110
113
  aria-checked={Boolean(isChecked)}
111
114
  onChange={handleChange}
115
+ {...inputProps}
112
116
  />
113
117
 
114
118
  <div className={`${CLASSNAME}__input-placeholder`}>
@@ -29,6 +29,36 @@ exports[`<Switch> Conditions should not display the \`helper\` if no \`label\` i
29
29
  </div>
30
30
  `;
31
31
 
32
+ exports[`<Switch> Props should use the given props while passing custom props to input 1`] = `
33
+ <div
34
+ className="lumx-switch lumx-switch--position-left lumx-switch--theme-light lumx-switch--is-unchecked"
35
+ >
36
+ <div
37
+ className="lumx-switch__input-wrapper"
38
+ >
39
+ <input
40
+ aria-checked={false}
41
+ aria-labelledby="labelledby-id"
42
+ className="lumx-switch__input-native"
43
+ id="switch-uid"
44
+ onChange={[Function]}
45
+ role="switch"
46
+ type="checkbox"
47
+ />
48
+ <div
49
+ className="lumx-switch__input-placeholder"
50
+ >
51
+ <div
52
+ className="lumx-switch__input-background"
53
+ />
54
+ <div
55
+ className="lumx-switch__input-indicator"
56
+ />
57
+ </div>
58
+ </div>
59
+ </div>
60
+ `;
61
+
32
62
  exports[`<Switch> Snapshots and structure should render correctly with a \`label\` and a \`helper\` 1`] = `
33
63
  <div
34
64
  className="lumx-switch lumx-switch--position-left lumx-switch--theme-light lumx-switch--is-unchecked"
@@ -1,11 +1,11 @@
1
+ import classNames from 'classnames';
2
+ import React, { forwardRef, ReactNode } from 'react';
3
+
1
4
  import { Alignment, Theme } from '@lumx/react';
2
5
  import { CSS_PREFIX } from '@lumx/react/constants';
3
6
  import { Comp, GenericProps, handleBasicClasses } from '@lumx/react/utils';
4
7
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
5
-
6
- import classNames from 'classnames';
7
- import React, { forwardRef, ReactNode } from 'react';
8
- import { useRovingTabIndex } from '../../hooks/useRovingTabIndex';
8
+ import { useRovingTabIndex } from '@lumx/react/_internal/hooks/useRovingTabIndex';
9
9
 
10
10
  export enum TabListLayout {
11
11
  clustered = 'clustered',
@@ -8,13 +8,13 @@ import classNames from 'classnames';
8
8
 
9
9
  import { Placement } from '@lumx/react/components/popover/Popover';
10
10
 
11
- import { DOCUMENT } from '@lumx/react/constants';
11
+ import { DOCUMENT, TOOLTIP_HOVER_DELAY, TOOLTIP_LONG_PRESS_DELAY } from '@lumx/react/constants';
12
12
 
13
13
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
14
14
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
15
15
 
16
+ import { useOpenHoverOrLongPress } from '@lumx/react/hooks/useOpenHoverOrLongPress';
16
17
  import { useInjectTooltipRef } from './useInjectTooltipRef';
17
- import { useTooltipOpen } from './useTooltipOpen';
18
18
 
19
19
  /** Position of the tooltip relative to the anchor element. */
20
20
  export type TooltipPlacement = Extract<Placement, 'top' | 'right' | 'bottom' | 'left'>;
@@ -49,7 +49,6 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
49
49
  * Component default props.
50
50
  */
51
51
  const DEFAULT_PROPS: Partial<TooltipProps> = {
52
- delay: 500,
53
52
  placement: Placement.BOTTOM,
54
53
  };
55
54
 
@@ -90,7 +89,11 @@ export const Tooltip: Comp<TooltipProps, HTMLDivElement> = forwardRef((props, re
90
89
  });
91
90
 
92
91
  const position = attributes?.popper?.['data-popper-placement'] ?? placement;
93
- const isOpen = useTooltipOpen(delay as number, anchorElement) || forceOpen;
92
+ const isOpen =
93
+ useOpenHoverOrLongPress(anchorElement, {
94
+ hover: { openDelay: delay ?? TOOLTIP_HOVER_DELAY.openDelay, closeDelay: TOOLTIP_HOVER_DELAY.closeDelay },
95
+ longPress: TOOLTIP_LONG_PRESS_DELAY,
96
+ }) || forceOpen;
94
97
  const wrappedChildren = useInjectTooltipRef(children, setAnchorElement, isOpen as boolean, id);
95
98
 
96
99
  return (
package/src/constants.ts CHANGED
@@ -1,4 +1,10 @@
1
- export { CSS_PREFIX, DIALOG_TRANSITION_DURATION, NOTIFICATION_TRANSITION_DURATION } from '@lumx/core/js/constants';
1
+ export {
2
+ CSS_PREFIX,
3
+ DIALOG_TRANSITION_DURATION,
4
+ NOTIFICATION_TRANSITION_DURATION,
5
+ TOOLTIP_HOVER_DELAY,
6
+ TOOLTIP_LONG_PRESS_DELAY,
7
+ } from '@lumx/core/js/constants';
2
8
 
3
9
  /**
4
10
  * Optional global `window` instance (not defined when running SSR).
@@ -0,0 +1,140 @@
1
+ import { onEscapePressed } from '@lumx/react/utils';
2
+ import { useEffect, useState } from 'react';
3
+ import { browserDoesNotSupportHover } from '@lumx/react/utils/browserDoesNotSupportHover';
4
+
5
+ interface OpenCloseConfig {
6
+ openDelay: number;
7
+ closeDelay: number;
8
+ }
9
+
10
+ interface Config {
11
+ hover: OpenCloseConfig;
12
+ longPress: OpenCloseConfig;
13
+ }
14
+
15
+ export const DEFAULT_CONFIG: Config = {
16
+ hover: {
17
+ openDelay: 500,
18
+ closeDelay: 0,
19
+ },
20
+ longPress: {
21
+ openDelay: 250,
22
+ closeDelay: 3000,
23
+ },
24
+ };
25
+
26
+ /**
27
+ * Hook controlling an open/close action on hover on device supporting pointer hover
28
+ * and on long press on device not supporting pointer hover.
29
+ *
30
+ * @param anchorElement Anchor element on which the hover or longPress is watched.
31
+ * @param config Open/close delay configuration.
32
+ * @return true/false boolean.
33
+ */
34
+ export function useOpenHoverOrLongPress(
35
+ anchorElement: HTMLElement | null,
36
+ config: { hover?: Partial<OpenCloseConfig>; longPress?: Partial<OpenCloseConfig> } = {},
37
+ ): boolean {
38
+ const [isOpen, setIsOpen] = useState(false);
39
+ const activation = browserDoesNotSupportHover() ? 'longPress' : 'hover';
40
+ const { openDelay: defaultOpenDelay, closeDelay: defaultCloseDelay } = DEFAULT_CONFIG[activation];
41
+ const { openDelay = defaultOpenDelay, closeDelay = defaultCloseDelay } = config?.[activation] || {};
42
+
43
+ useEffect(() => {
44
+ if (!anchorElement) {
45
+ return undefined;
46
+ }
47
+ let timer: number | undefined;
48
+ let openStartTime: number | undefined;
49
+ let shouldOpen: boolean | undefined;
50
+
51
+ // Run timer to defer updating the isOpen state.
52
+ const deferUpdate = (duration: number) => {
53
+ if (timer) clearTimeout(timer);
54
+ timer = setTimeout(() => {
55
+ setIsOpen(!!shouldOpen);
56
+ }, duration) as any;
57
+ };
58
+
59
+ const hasTouch = 'ontouchstart' in window;
60
+
61
+ // Open (or/and cancel closing).
62
+ const open = () => {
63
+ if (shouldOpen && !timer) return;
64
+ shouldOpen = true;
65
+ openStartTime = Date.now();
66
+ deferUpdate(openDelay);
67
+ };
68
+
69
+ // Close or cancel opening
70
+ const close = (overrideDelay = closeDelay) => {
71
+ if (!shouldOpen && !timer) return;
72
+ shouldOpen = false;
73
+ deferUpdate(overrideDelay);
74
+ };
75
+ const closeImmediately = () => close(0);
76
+
77
+ /**
78
+ * Handle touchend event
79
+ * If `touchend` comes before the open delay => cancel open (close immediate).
80
+ * Else if `touchend` comes after the open delay => open takes priority, the anchor's default touch end event is prevented.
81
+ */
82
+ const touchEnd = (evt: Event) => {
83
+ if (!openStartTime) return;
84
+ if (Date.now() - openStartTime >= openDelay) {
85
+ // Tooltip take priority, event prevented.
86
+ evt.stopPropagation();
87
+ evt.preventDefault();
88
+ anchorElement.focus();
89
+ // Close with delay.
90
+ close();
91
+ } else {
92
+ // Close immediately.
93
+ closeImmediately();
94
+ }
95
+ };
96
+
97
+ const events: Array<[Node, Event['type'], any]> = [];
98
+
99
+ // Long press activation.
100
+ if (activation === 'longPress') {
101
+ events.push(
102
+ [anchorElement, hasTouch ? 'touchstart' : 'mousedown', open],
103
+ [anchorElement, hasTouch ? 'touchend' : 'mouseup', touchEnd],
104
+ );
105
+ }
106
+
107
+ // Hover activation.
108
+ if (activation === 'hover') {
109
+ events.push(
110
+ [anchorElement, 'mouseenter', open],
111
+ [anchorElement, 'mouseleave', close],
112
+ [anchorElement, 'mouseup', closeImmediately],
113
+ );
114
+ }
115
+
116
+ // Events always applied no matter the browser:
117
+ events.push(
118
+ // Open on focus.
119
+ [anchorElement, 'focusin', open],
120
+ // Close on lost focus.
121
+ [anchorElement, 'focusout', closeImmediately],
122
+ // Close on ESC keydown
123
+ [anchorElement, 'keydown', onEscapePressed(closeImmediately)],
124
+ );
125
+
126
+ // Attach events
127
+ for (const [node, eventType, evenHandler] of events) {
128
+ node.addEventListener(eventType, evenHandler);
129
+ }
130
+ return () => {
131
+ // Detach events.
132
+ for (const [node, eventType, evenHandler] of events) {
133
+ node.removeEventListener(eventType, evenHandler);
134
+ }
135
+ closeImmediately();
136
+ };
137
+ }, [activation, anchorElement, closeDelay, openDelay]);
138
+
139
+ return isOpen;
140
+ }
@@ -1,6 +1,6 @@
1
1
  import React, { createContext, useContext, useEffect } from 'react';
2
2
  import pull from 'lodash/pull';
3
- import { ClickAwayParameters, useClickAway } from '@lumx/react/hooks/useClickAway';
3
+ import { ClickAwayParameters, useClickAway } from '@lumx/react/_internal/hooks/useClickAway';
4
4
 
5
5
  const ClickAwayAncestorContext = createContext<ClickAwayParameters['refs'] | null>(null);
6
6
 
@@ -0,0 +1,24 @@
1
+ import { browserDoesNotSupportHover } from '@lumx/react/utils/browserDoesNotSupportHover';
2
+
3
+ const originalMatchMedia = global.matchMedia;
4
+
5
+ describe('browserDoesNotSupportHover', () => {
6
+ afterAll(() => {
7
+ global.matchMedia = originalMatchMedia;
8
+ });
9
+
10
+ it('should return `false` on browsers that do not support matchMedia', () => {
11
+ global.matchMedia = undefined;
12
+ expect(browserDoesNotSupportHover()).toBe(false);
13
+ });
14
+
15
+ it('should return `false` on browsers that support matchMedia and does support hover', () => {
16
+ global.matchMedia = () => ({ matches: false });
17
+ expect(browserDoesNotSupportHover()).toBe(false);
18
+ });
19
+
20
+ it('should return `true` on browsers that support matchMedia and does not support hover', () => {
21
+ global.matchMedia = () => ({ matches: true });
22
+ expect(browserDoesNotSupportHover()).toBe(true);
23
+ });
24
+ });
@@ -0,0 +1,2 @@
1
+ /** Return true if the browser does not support pointer hover */
2
+ export const browserDoesNotSupportHover = (): boolean => !!window.matchMedia?.('(hover: none)').matches;
package/types.d.ts CHANGED
@@ -599,6 +599,8 @@ export interface CheckboxProps extends GenericProps {
599
599
  value?: string;
600
600
  /** On change callback. */
601
601
  onChange?(isChecked: boolean, value?: string, name?: string, event?: SyntheticEvent): void;
602
+ /** optional props for input */
603
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
602
604
  }
603
605
  /**
604
606
  * Checkbox component.
@@ -666,7 +668,7 @@ export interface ChipGroupProps extends GenericProps {
666
668
  children: ReactNode;
667
669
  }
668
670
  export declare const ChipGroup: Comp<ChipGroupProps, HTMLDivElement> & {
669
- useChipGroupNavigation: import("../../hooks/useChipGroupNavigation").useChipGroupNavigationType<any>;
671
+ useChipGroupNavigation: import("../../_internal/hooks/useChipGroupNavigation").useChipGroupNavigationType<any>;
670
672
  };
671
673
  /**
672
674
  * Comment block variants.
@@ -1480,7 +1482,7 @@ export interface ListProps extends GenericProps {
1480
1482
  onListItemSelected?(key: Key, index: number, evt: SyntheticEvent): void;
1481
1483
  }
1482
1484
  export declare const List: Comp<ListProps, HTMLUListElement> & {
1483
- useKeyboardListNavigation: import("../../hooks/useKeyboardListNavigation").useKeyboardListNavigationType;
1485
+ useKeyboardListNavigation: import("../../_internal/hooks/useKeyboardListNavigation").useKeyboardListNavigationType;
1484
1486
  };
1485
1487
  export declare type ListItemSize = Extract<Size, "tiny" | "regular" | "big" | "huge">;
1486
1488
  /**
@@ -2167,6 +2169,8 @@ export interface SwitchProps extends GenericProps {
2167
2169
  value?: string;
2168
2170
  /** On change callback. */
2169
2171
  onChange?(isChecked: boolean, value?: string, name?: string, event?: SyntheticEvent): void;
2172
+ /** optional props for input */
2173
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
2170
2174
  }
2171
2175
  /**
2172
2176
  * Switch component.
package/esm/index2.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index2.js","sources":["../../../../node_modules/uid/dist/index.mjs"],"sourcesContent":["var IDX=256, HEX=[], SIZE=256, BUFFER;\nwhile (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);\n\nexport function uid(len) {\n\tvar i=0, tmp=(len || 11);\n\tif (!BUFFER || ((IDX + tmp) > SIZE*2)) {\n\t\tfor (BUFFER='',IDX=0; i < SIZE; i++) {\n\t\t\tBUFFER += HEX[Math.random() * 256 | 0];\n\t\t}\n\t}\n\n\treturn BUFFER.substring(IDX, IDX++ + tmp);\n}\n"],"names":[],"mappings":"AAAA,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;AACtC,OAAO,GAAG,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC/D;AACO,SAAS,GAAG,CAAC,GAAG,EAAE;AACzB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAC1B,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE;AACxC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;AACvC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAC1C,GAAG;AACH,EAAE;AACF;AACA,CAAC,OAAO,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;AAC3C;;;;"}
@@ -1,112 +0,0 @@
1
- import { Callback, onEscapePressed } from '@lumx/react/utils';
2
- import { useEffect, useRef, useState } from 'react';
3
- import pull from 'lodash/pull';
4
- import debounce from 'lodash/debounce';
5
-
6
- type Tooltip = { open: Callback; close: Callback; anchorElement: HTMLElement };
7
-
8
- /**
9
- * This singleton handle a global `mouseover` event listener on the `document` in order to toggle tooltips when
10
- * entering and leaving their anchor element.
11
- */
12
- const tooltipMouseToggle = (() => {
13
- /** List of tooltips to toggle on anchor enter/leave. */
14
- let tooltips: Array<Tooltip> | undefined;
15
-
16
- /** Global listener added on the document. */
17
- let globalListener: undefined | ((evt: MouseEvent) => void);
18
-
19
- function addGlobalListener() {
20
- if (globalListener) return;
21
- globalListener = debounce((evt) => {
22
- if (!tooltips || !evt.target) return;
23
- for (const { open, close, anchorElement } of tooltips) {
24
- if (anchorElement.contains(evt.target as any)) {
25
- open();
26
- } else {
27
- close();
28
- }
29
- }
30
- }, 10);
31
- document.addEventListener('mouseover', globalListener);
32
- }
33
-
34
- function removeGlobalListener() {
35
- if (!globalListener) return;
36
- document.removeEventListener('mouseover', globalListener);
37
- globalListener = undefined;
38
- }
39
-
40
- return {
41
- addTooltip(tooltip: Tooltip) {
42
- if (!tooltips) {
43
- tooltips = [];
44
- addGlobalListener();
45
- }
46
- tooltips.push(tooltip);
47
- },
48
- removeTooltip(actions: Tooltip) {
49
- if (!tooltips) return;
50
- pull(tooltips, actions);
51
- if (tooltips.length === 0) {
52
- removeGlobalListener();
53
- tooltips = undefined;
54
- }
55
- },
56
- };
57
- })();
58
-
59
- /**
60
- * Hook controlling tooltip visibility using mouse hover the anchor and delay.
61
- *
62
- * @param delay Delay in millisecond to display the tooltip.
63
- * @param anchorElement Tooltip anchor element.
64
- * @return whether or not to show the tooltip.
65
- */
66
- export function useTooltipOpen(delay: number, anchorElement: HTMLElement | null): boolean {
67
- const timer = useRef<number>();
68
- const shouldOpen = useRef<boolean>(false);
69
- const [isOpen, setIsOpen] = useState(false);
70
-
71
- useEffect(() => {
72
- if (!anchorElement) {
73
- return undefined;
74
- }
75
- const tooltip: Tooltip = {
76
- anchorElement,
77
- open() {
78
- if (!shouldOpen.current) {
79
- shouldOpen.current = true;
80
- timer.current = setTimeout(() => {
81
- setIsOpen(shouldOpen.current);
82
- }, delay) as any;
83
- }
84
- },
85
- close() {
86
- if (timer.current) {
87
- clearTimeout(timer.current);
88
- timer.current = undefined;
89
- }
90
- if (shouldOpen.current) {
91
- shouldOpen.current = false;
92
- setIsOpen(shouldOpen.current);
93
- }
94
- },
95
- };
96
- const keydown = onEscapePressed(tooltip.close);
97
-
98
- tooltipMouseToggle.addTooltip(tooltip);
99
- anchorElement.addEventListener('focusin', tooltip.open);
100
- anchorElement.addEventListener('focusout', tooltip.close);
101
- anchorElement.addEventListener('keydown', keydown);
102
- return () => {
103
- tooltipMouseToggle.removeTooltip(tooltip);
104
- anchorElement.removeEventListener('focusin', tooltip.open);
105
- anchorElement.removeEventListener('focusout', tooltip.close);
106
- anchorElement.removeEventListener('keydown', keydown);
107
- tooltip.close();
108
- };
109
- }, [anchorElement, delay, timer, shouldOpen]);
110
-
111
- return isOpen;
112
- }