@lumx/react 2.2.20-alpha.xss.datatable → 2.2.21

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 (81) hide show
  1. package/esm/_internal/ClickAwayProvider.js +90 -12
  2. package/esm/_internal/ClickAwayProvider.js.map +1 -1
  3. package/esm/_internal/DatePickerField.js +18 -11
  4. package/esm/_internal/DatePickerField.js.map +1 -1
  5. package/esm/_internal/Dialog2.js +2 -2
  6. package/esm/_internal/Dialog2.js.map +1 -1
  7. package/esm/_internal/GenericBlock.js +90 -0
  8. package/esm/_internal/GenericBlock.js.map +1 -0
  9. package/esm/_internal/Lightbox2.js +2 -2
  10. package/esm/_internal/Lightbox2.js.map +1 -1
  11. package/esm/_internal/LinkPreview.js +22 -12
  12. package/esm/_internal/LinkPreview.js.map +1 -1
  13. package/esm/_internal/Popover2.js +21 -8
  14. package/esm/_internal/Popover2.js.map +1 -1
  15. package/esm/_internal/SelectMultiple.js +16 -4
  16. package/esm/_internal/SelectMultiple.js.map +1 -1
  17. package/esm/_internal/alert-dialog.js +2 -2
  18. package/esm/_internal/autocomplete.js +2 -1
  19. package/esm/_internal/autocomplete.js.map +1 -1
  20. package/esm/_internal/button.js +2 -1
  21. package/esm/_internal/button.js.map +1 -1
  22. package/esm/_internal/comment-block.js +2 -1
  23. package/esm/_internal/comment-block.js.map +1 -1
  24. package/esm/_internal/date-picker.js +3 -2
  25. package/esm/_internal/date-picker.js.map +1 -1
  26. package/esm/_internal/dialog.js +2 -2
  27. package/esm/_internal/dropdown.js +2 -1
  28. package/esm/_internal/dropdown.js.map +1 -1
  29. package/esm/_internal/expansion-panel.js +1 -1
  30. package/esm/_internal/generic-block.js +12 -0
  31. package/esm/_internal/generic-block.js.map +1 -0
  32. package/esm/_internal/lightbox.js +3 -2
  33. package/esm/_internal/lightbox.js.map +1 -1
  34. package/esm/_internal/popover.js +2 -1
  35. package/esm/_internal/popover.js.map +1 -1
  36. package/esm/_internal/select.js +2 -1
  37. package/esm/_internal/select.js.map +1 -1
  38. package/esm/_internal/side-navigation.js +2 -1
  39. package/esm/_internal/side-navigation.js.map +1 -1
  40. package/esm/_internal/slideshow.js +2 -1
  41. package/esm/_internal/slideshow.js.map +1 -1
  42. package/esm/_internal/text-field.js +2 -1
  43. package/esm/_internal/text-field.js.map +1 -1
  44. package/esm/_internal/tooltip.js +2 -1
  45. package/esm/_internal/tooltip.js.map +1 -1
  46. package/esm/_internal/type.js.map +1 -1
  47. package/esm/_internal/useFocusTrap.js +62 -78
  48. package/esm/_internal/useFocusTrap.js.map +1 -1
  49. package/esm/index.js +3 -2
  50. package/esm/index.js.map +1 -1
  51. package/package.json +5 -5
  52. package/src/components/date-picker/DatePickerField.tsx +15 -16
  53. package/src/components/date-picker/types.ts +2 -2
  54. package/src/components/dialog/Dialog.stories.tsx +57 -13
  55. package/src/components/dialog/Dialog.tsx +1 -1
  56. package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +82 -14
  57. package/src/components/generic-block/GenericBlock.stories.tsx +149 -0
  58. package/src/components/generic-block/GenericBlock.test.tsx +28 -0
  59. package/src/components/generic-block/GenericBlock.tsx +120 -0
  60. package/src/components/generic-block/__snapshots__/GenericBlock.test.tsx.snap +92 -0
  61. package/src/components/generic-block/index.ts +1 -0
  62. package/src/components/lightbox/Lightbox.tsx +1 -1
  63. package/src/components/link-preview/LinkPreview.test.tsx +50 -55
  64. package/src/components/link-preview/LinkPreview.tsx +43 -16
  65. package/src/components/popover/Popover.tsx +20 -4
  66. package/src/components/select/Select.stories.tsx +2 -0
  67. package/src/components/select/Select.tsx +11 -1
  68. package/src/components/select/SelectMultiple.stories.tsx +2 -0
  69. package/src/components/select/SelectMultiple.tsx +11 -1
  70. package/src/components/select/constants.ts +2 -0
  71. package/src/components/table/__snapshots__/Table.test.tsx.snap +5 -0
  72. package/src/hooks/useCallbackOnEscape.ts +21 -13
  73. package/src/hooks/useFocusTrap.ts +68 -51
  74. package/src/index.ts +1 -0
  75. package/src/stories/generated/GenericBlock/Demos.stories.tsx +6 -0
  76. package/src/utils/focus/getFirstAndLastFocusable.test.ts +6 -0
  77. package/src/utils/focus/getFirstAndLastFocusable.ts +2 -2
  78. package/src/utils/makeListenerTowerContext.ts +32 -0
  79. package/src/utils/type.ts +3 -0
  80. package/types.d.ts +56 -6
  81. package/src/components/link-preview/__snapshots__/LinkPreview.test.tsx.snap +0 -51
@@ -1,5 +1,5 @@
1
1
  import { detectOverflow } from '@popperjs/core';
2
- import React, { forwardRef, ReactNode, RefObject, useEffect, useMemo, useRef, useState } from 'react';
2
+ import React, { forwardRef, ReactNode, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { usePopper } from 'react-popper';
5
5
 
@@ -13,6 +13,7 @@ import { ClickAwayProvider } from '@lumx/react/utils/ClickAwayProvider';
13
13
  import { Comp, GenericProps, getRootClassName, handleBasicClasses, ValueOf } from '@lumx/react/utils';
14
14
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
15
15
  import { useFocusWithin } from '@lumx/react/hooks/useFocusWithin';
16
+ import { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';
16
17
 
17
18
  /**
18
19
  * Different possible placements for the popover.
@@ -90,6 +91,8 @@ export interface PopoverProps extends GenericProps {
90
91
  isOpen: boolean;
91
92
  /** Offset placement relative to anchor. */
92
93
  offset?: Offset;
94
+ /** Reference to the parent element that triggered the popover (will get back focus on close or else fallback on the anchor element). */
95
+ parentElement?: RefObject<HTMLElement>;
93
96
  /** Placement relative to anchor. */
94
97
  placement?: Placement;
95
98
  /** Whether the popover should be rendered into a DOM node that exists outside the DOM hierarchy of the parent component. */
@@ -212,6 +215,7 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
212
215
  isOpen,
213
216
  offset,
214
217
  onClose,
218
+ parentElement,
215
219
  placement,
216
220
  style,
217
221
  usePortal,
@@ -245,7 +249,8 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
245
249
  });
246
250
 
247
251
  /** Action on close */
248
- const handleClose = () => {
252
+ // eslint-disable-next-line react-hooks/rules-of-hooks
253
+ const handleClose = useCallback(() => {
249
254
  if (!onClose) {
250
255
  return;
251
256
  }
@@ -256,11 +261,22 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
256
261
  * unless specifically requested not to.
257
262
  */
258
263
  if (isFocusedWithin.current && focusAnchorOnClose) {
259
- anchorRef.current?.focus();
264
+ if (parentElement?.current) {
265
+ parentElement?.current.focus();
266
+ }
267
+
268
+ const firstFocusable = anchorRef?.current && getFirstAndLastFocusable(anchorRef?.current).first;
269
+ if (firstFocusable) {
270
+ // Focus the first focusable element in anchor.
271
+ firstFocusable.focus();
272
+ } else {
273
+ // Fallback on the anchor element.
274
+ anchorRef?.current?.focus();
275
+ }
260
276
  }
261
277
 
262
278
  onClose();
263
- };
279
+ }, [anchorRef, focusAnchorOnClose, onClose, parentElement]);
264
280
 
265
281
  const modifiers: any = [];
266
282
  const actualOffset: [number, number] = [offset?.along ?? 0, (offset?.away ?? 0) + (hasArrow ? ARROW_SIZE : 0)];
@@ -1,3 +1,4 @@
1
+ import { mdiBullhornOutline } from '@lumx/icons/';
1
2
  import { List, ListItem, Select, Size, TextField } from '@lumx/react';
2
3
  import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
3
4
  import { text } from '@storybook/addon-knobs';
@@ -32,6 +33,7 @@ export const SimpleSelect = ({ theme }: any) => {
32
33
  theme={theme}
33
34
  onInputClick={toggleSelect}
34
35
  onDropdownClose={closeSelect}
36
+ icon={mdiBullhornOutline}
35
37
  >
36
38
  <List isClickable>
37
39
  {CHOICES.length > 0
@@ -5,7 +5,7 @@ import lodashIsEmpty from 'lodash/isEmpty';
5
5
 
6
6
  import { mdiAlertCircle, mdiCheckCircle, mdiCloseCircle, mdiMenuDown } from '@lumx/icons';
7
7
 
8
- import { Emphasis, Size } from '@lumx/react/components';
8
+ import { Emphasis, Size, Theme } from '@lumx/react/components';
9
9
  import { IconButton } from '@lumx/react/components/button/IconButton';
10
10
  import { Chip } from '@lumx/react/components/chip/Chip';
11
11
  import { Icon } from '@lumx/react/components/icon/Icon';
@@ -46,6 +46,7 @@ const SelectField: React.FC<SelectProps> = ({
46
46
  handleKeyboardNav,
47
47
  hasError,
48
48
  hasInputClear,
49
+ icon,
49
50
  id,
50
51
  isDisabled,
51
52
  isEmpty,
@@ -89,6 +90,15 @@ const SelectField: React.FC<SelectProps> = ({
89
90
  aria-disabled={isDisabled || undefined}
90
91
  {...forwardedProps}
91
92
  >
93
+ {icon && (
94
+ <Icon
95
+ className={`${CLASSNAME}__input-icon`}
96
+ color={theme === Theme.dark ? 'light' : undefined}
97
+ icon={icon}
98
+ size={Size.xs}
99
+ />
100
+ )}
101
+
92
102
  <div
93
103
  className={classNames([
94
104
  `${CLASSNAME}__input-native`,
@@ -1,4 +1,5 @@
1
1
  /* istanbul ignore file */
2
+ import { mdiTram } from '@lumx/icons/';
2
3
  import { Chip, List, ListItem, SelectMultiple, Size } from '@lumx/react';
3
4
  import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
4
5
  import noop from 'lodash/noop';
@@ -40,6 +41,7 @@ export const DefaultSelectMultiple = ({ theme }: any) => {
40
41
  theme={theme}
41
42
  onInputClick={toggleSelect}
42
43
  onDropdownClose={closeSelect}
44
+ icon={mdiTram}
43
45
  >
44
46
  <List isClickable>
45
47
  {CHOICES.length > 0
@@ -4,7 +4,7 @@ import classNames from 'classnames';
4
4
 
5
5
  import { mdiAlertCircle, mdiCheckCircle, mdiClose, mdiCloseCircle, mdiMenuDown } from '@lumx/icons';
6
6
 
7
- import { Size } from '@lumx/react/components';
7
+ import { Size, Theme } from '@lumx/react/components';
8
8
  import { Chip } from '@lumx/react/components/chip/Chip';
9
9
  import { Icon } from '@lumx/react/components/icon/Icon';
10
10
  import { InputLabel } from '@lumx/react/components/input-label/InputLabel';
@@ -59,6 +59,7 @@ export const SelectMultipleField: React.FC<SelectMultipleProps> = ({
59
59
  anchorRef,
60
60
  handleKeyboardNav,
61
61
  hasError,
62
+ icon,
62
63
  id,
63
64
  isDisabled,
64
65
  isEmpty,
@@ -102,6 +103,15 @@ export const SelectMultipleField: React.FC<SelectMultipleProps> = ({
102
103
  aria-disabled={isDisabled || undefined}
103
104
  {...forwardedProps}
104
105
  >
106
+ {icon && (
107
+ <Icon
108
+ className={`${CLASSNAME}__input-icon`}
109
+ color={theme === Theme.dark ? 'light' : undefined}
110
+ icon={icon}
111
+ size={Size.xs}
112
+ />
113
+ )}
114
+
105
115
  <div className={`${CLASSNAME}__chips`}>
106
116
  {!isEmpty &&
107
117
  value.map((val, index) => selectedChipRender?.(val, index, onClear, isDisabled, theme))}
@@ -21,6 +21,8 @@ export interface CoreSelectProps extends GenericProps {
21
21
  helper?: string;
22
22
  /** Whether the select should close on click. */
23
23
  closeOnClick?: boolean;
24
+ /** Icon (SVG path). */
25
+ icon?: string;
24
26
  /** Whether the component is disabled or not. */
25
27
  isDisabled?: boolean;
26
28
  /** Whether the component is required or not. */
@@ -3,6 +3,11 @@
3
3
  exports[`<Table> Snapshots and structure should render story 'Default' 1`] = `
4
4
  <table
5
5
  className="lumx-table lumx-table--has-dividers lumx-table--theme-light"
6
+ style={
7
+ Object {
8
+ "minWidth": 620,
9
+ }
10
+ }
6
11
  >
7
12
  <TableHeader>
8
13
  <TableRow>
@@ -1,25 +1,33 @@
1
1
  import { DOCUMENT } from '@lumx/react/constants';
2
2
  import { Callback, onEscapePressed } from '@lumx/react/utils';
3
3
  import { useEffect } from 'react';
4
+ import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
5
+
6
+ const LISTENERS = makeListenerTowerContext();
4
7
 
5
8
  /**
6
- * Triggers a callback when the escape key is pressed.
9
+ * Register a global listener on 'Escape' key pressed.
10
+ *
11
+ * If multiple listener are registered, only the last one is maintained. When a listener is unregistered, the previous
12
+ * one gets activated again.
7
13
  *
8
14
  * @param callback Callback
9
15
  * @param closeOnEscape Disables the hook when false
10
- * @param rootElement Element on which to listen the escape key
11
16
  */
12
- export function useCallbackOnEscape(
13
- callback: Callback | undefined,
14
- closeOnEscape = true,
15
- rootElement = DOCUMENT?.body,
16
- ) {
17
+ export function useCallbackOnEscape(callback: Callback | undefined, closeOnEscape = true) {
17
18
  useEffect(() => {
18
- if (closeOnEscape && callback && rootElement) {
19
- const onKeyDown = onEscapePressed(callback);
20
- rootElement.addEventListener('keydown', onKeyDown);
21
- return () => rootElement.removeEventListener('keydown', onKeyDown);
19
+ const rootElement = DOCUMENT?.body;
20
+ if (!closeOnEscape || !callback || !rootElement) {
21
+ return undefined;
22
22
  }
23
- return undefined;
24
- }, [callback, closeOnEscape, rootElement]);
23
+ const onKeyDown = onEscapePressed(callback);
24
+
25
+ const listener: Listener = {
26
+ enable: () => rootElement.addEventListener('keydown', onKeyDown),
27
+ disable: () => rootElement.removeEventListener('keydown', onKeyDown),
28
+ };
29
+
30
+ LISTENERS.register(listener);
31
+ return () => LISTENERS.unregister(listener);
32
+ }, [callback, closeOnEscape]);
25
33
  }
@@ -2,67 +2,84 @@ import { useEffect } from 'react';
2
2
 
3
3
  import { DOCUMENT } from '@lumx/react/constants';
4
4
  import { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';
5
+ import { Falsy } from '@lumx/react/utils';
6
+ import { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';
7
+
8
+ const FOCUS_TRAPS = makeListenerTowerContext();
5
9
 
6
10
  /**
7
- * Add a key down event handler to the given root element (document.body by default) to trap the move of focus
8
- * (TAB and SHIFT-TAB keys) inside the given focusZoneElement.
9
- * Will focus the given focus element when activating the focus trap.
11
+ * Trap 'Tab' focus switch inside the `focusZoneElement`.
12
+ *
13
+ * If multiple focus trap are activated, only the last one is maintained and when a focus trap closes, the previous one
14
+ * gets activated again.
10
15
  *
11
16
  * @param focusZoneElement The element in which to trap the focus.
12
- * @param focusElement The element to focus when the focus trap is activated.
13
- * @param rootElement The element on which the key down event will be placed.
17
+ * @param focusElement The element to focus when the focus trap is activated (otherwise the first focusable element
18
+ * will be focused).
14
19
  */
15
- export function useFocusTrap(
16
- focusZoneElement: HTMLElement | null,
17
- focusElement?: HTMLElement | null,
18
- rootElement = DOCUMENT?.body,
19
- ): void {
20
+ export function useFocusTrap(focusZoneElement: HTMLElement | Falsy, focusElement?: HTMLElement | null): void {
20
21
  useEffect(() => {
21
- if (rootElement && focusZoneElement) {
22
- (document.activeElement as HTMLElement)?.blur();
23
- if (focusElement) {
24
- focusElement.focus();
22
+ // Body element can be undefined in SSR context.
23
+ const rootElement = DOCUMENT?.body;
24
+
25
+ if (!rootElement || !focusZoneElement) {
26
+ return undefined;
27
+ }
28
+
29
+ // Trap 'Tab' key down focus switch into the focus zone.
30
+ const trapTabFocusInFocusZone = (evt: KeyboardEvent) => {
31
+ const { key } = evt;
32
+ if (key !== 'Tab') {
33
+ return;
25
34
  }
35
+ const focusable = getFirstAndLastFocusable(focusZoneElement);
26
36
 
27
- const onKeyDown = (evt: KeyboardEvent) => {
28
- const { key } = evt;
29
- if (key !== 'Tab') {
30
- return;
31
- }
32
- const focusable = getFirstAndLastFocusable(focusZoneElement);
37
+ // Prevent focus switch if no focusable available.
38
+ if (!focusable.first) {
39
+ evt.preventDefault();
40
+ return;
41
+ }
33
42
 
34
- // Prevent focus switch if no focusable available.
35
- if (!focusable.first) {
36
- evt.preventDefault();
37
- return;
38
- }
43
+ if (
44
+ // No previous focus
45
+ !document.activeElement ||
46
+ // Previous focus is at the end of the focus zone.
47
+ (!evt.shiftKey && document.activeElement === focusable.last) ||
48
+ // Previous focus is outside the focus zone
49
+ !focusZoneElement.contains(document.activeElement)
50
+ ) {
51
+ focusable.first.focus();
52
+ evt.preventDefault();
53
+ return;
54
+ }
39
55
 
40
- if (
41
- // No previous focus
42
- !document.activeElement ||
43
- // Previous focus is at the end of the focus zone.
44
- (!evt.shiftKey && document.activeElement === focusable.last) ||
45
- // Previous focus is outside the focus zone
46
- !focusZoneElement.contains(document.activeElement)
47
- ) {
48
- focusable.first.focus();
49
- evt.preventDefault();
50
- return;
51
- }
56
+ if (
57
+ // Focus order reversed
58
+ evt.shiftKey &&
59
+ // Previous focus is at the start of the focus zone.
60
+ document.activeElement === focusable.first
61
+ ) {
62
+ focusable.last.focus();
63
+ evt.preventDefault();
64
+ }
65
+ };
52
66
 
53
- if (
54
- // Focus order reversed
55
- evt.shiftKey &&
56
- // Previous focus is at the start of the focus zone.
57
- document.activeElement === focusable.first
58
- ) {
59
- focusable.last.focus();
60
- evt.preventDefault();
61
- }
62
- };
63
- rootElement.addEventListener('keydown', onKeyDown);
64
- return () => rootElement.removeEventListener('keydown', onKeyDown);
67
+ const focusTrap: Listener = {
68
+ enable: () => rootElement.addEventListener('keydown', trapTabFocusInFocusZone),
69
+ disable: () => rootElement.removeEventListener('keydown', trapTabFocusInFocusZone),
70
+ };
71
+
72
+ // SETUP:
73
+ if (focusElement && focusZoneElement.contains(focusElement)) {
74
+ // Focus the given element.
75
+ focusElement.focus();
76
+ } else {
77
+ // Focus the first focusable element in the zone.
78
+ getFirstAndLastFocusable(focusZoneElement).first?.focus();
65
79
  }
66
- return undefined;
67
- }, [focusElement, focusZoneElement, rootElement]);
80
+ FOCUS_TRAPS.register(focusTrap);
81
+
82
+ // TEARDOWN:
83
+ return () => FOCUS_TRAPS.unregister(focusTrap);
84
+ }, [focusElement, focusZoneElement]);
68
85
  }
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ export * from './components/dropdown';
15
15
  export * from './components/expansion-panel';
16
16
  export * from './components/flag';
17
17
  export * from './components/flex-box';
18
+ export * from './components/generic-block';
18
19
  export * from './components/grid';
19
20
  export * from './components/icon';
20
21
  export * from './components/image-block';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * File generated when storybook is started. Do not edit directly!
3
+ */
4
+ export default { title: 'LumX components/generic-block/GenericBlock Demos' };
5
+
6
+ export { App as Default } from './default';
@@ -124,5 +124,11 @@ describe(getFirstAndLastFocusable.name, () => {
124
124
  const focusable = getFirstAndLastFocusable(element);
125
125
  expect(focusable.first).toMatchInlineSnapshot(`<button />`);
126
126
  });
127
+
128
+ it('should skip hidden input', () => {
129
+ const element = htmlToElement(`<div><input hidden /><button /></div>`);
130
+ const focusable = getFirstAndLastFocusable(element);
131
+ expect(focusable.first).toMatchInlineSnapshot(`<button />`);
132
+ });
127
133
  });
128
134
  });
@@ -1,8 +1,8 @@
1
1
  /** CSS selector listing all tabbable elements. */
2
- const TABBABLE_ELEMENTS_SELECTOR = `a[href], button, textarea, input:not([type="hidden"]), [tabindex]`;
2
+ const TABBABLE_ELEMENTS_SELECTOR = `a[href], button, textarea, input:not([type="hidden"]):not([hidden]), [tabindex]`;
3
3
 
4
4
  /** CSS selector matching element that are disabled (should not receive focus). */
5
- const DISABLED_SELECTOR = `[tabindex="-1"], [disabled]:not([disabled="false"]), [aria-disabled]:not([aria-disabled="false"])`;
5
+ const DISABLED_SELECTOR = `[hidden], [tabindex="-1"], [disabled]:not([disabled="false"]), [aria-disabled]:not([aria-disabled="false"])`;
6
6
 
7
7
  const isNotDisabled = (element: HTMLElement) => !element.matches(DISABLED_SELECTOR);
8
8
 
@@ -0,0 +1,32 @@
1
+ import last from 'lodash/last';
2
+ import pull from 'lodash/pull';
3
+
4
+ export type Listener = { enable(): void; disable(): void };
5
+
6
+ /**
7
+ * Keep track of listeners, only the last registered listener gets activated at any point (previously registered
8
+ * listener are disabled).
9
+ * When a listener gets unregistered, the previously registered listener gets enabled again.
10
+ */
11
+ export function makeListenerTowerContext() {
12
+ const LISTENERS: Listener[] = [];
13
+
14
+ return {
15
+ register(listener: Listener) {
16
+ // Disable previous listener.
17
+ last(LISTENERS)?.disable();
18
+ // Keep track of current listener.
19
+ LISTENERS.push(listener);
20
+ // Enable current listener.
21
+ listener.enable();
22
+ },
23
+ unregister(listener: Listener) {
24
+ // Disable current listener.
25
+ listener.disable();
26
+ // Remove current listener.
27
+ pull(LISTENERS, listener);
28
+ // Enable previous listener.
29
+ last(LISTENERS)?.enable();
30
+ },
31
+ };
32
+ }
package/src/utils/type.ts CHANGED
@@ -31,6 +31,9 @@ export type Comp<P, T = HTMLElement> = {
31
31
  className?: string;
32
32
  };
33
33
 
34
+ /** Union type of all heading elements */
35
+ export type HeadingElement = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
36
+
34
37
  /**
35
38
  * Define a generic props types.
36
39
  */
package/types.d.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  // Generated by dts-bundle-generator v5.6.0
2
2
 
3
- /// <reference types="react" />
3
+ /// <reference types="cheerio" />
4
+ /// <reference types="node" />
5
+ /// <reference types="prop-types" />
6
+
7
+ import * as CSS from 'csstype';
8
+ import * as PropTypes from 'prop-types';
9
+ import React from 'react';
10
+ import { AriaAttributes, ButtonHTMLAttributes, CSSProperties, DetailedHTMLProps, ImgHTMLAttributes, InputHTMLAttributes, Key, KeyboardEventHandler, MouseEventHandler, ReactElement, ReactNode, Ref, RefObject, SetStateAction, SyntheticEvent } from 'react';
4
11
 
5
12
  /** Get types of the values of a record. */
6
13
  export declare type ValueOf<T extends Record<any, any>> = T[keyof T];
@@ -18,6 +25,8 @@ export declare type Comp<P, T = HTMLElement> = {
18
25
  /** Component base class name. */
19
26
  className?: string;
20
27
  };
28
+ /** Union type of all heading elements */
29
+ export declare type HeadingElement = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
21
30
  /**
22
31
  * Define a generic props types.
23
32
  */
@@ -741,7 +750,7 @@ export interface DatePickerProps extends GenericProps {
741
750
  /** Props to pass to the previous month button (minus those already set by the DatePickerControlled props). */
742
751
  previousButtonProps: Pick<IconButtonProps, "label"> & Omit<IconButtonProps, "label" | "onClick" | "icon" | "emphasis">;
743
752
  /** Reference to the <button> element corresponding to the current date or the selected date. */
744
- todayOrSelectedDateRef?: RefObject<HTMLButtonElement>;
753
+ todayOrSelectedDateRef?: Ref<HTMLButtonElement>;
745
754
  /** Currently selected date. */
746
755
  value: Date | undefined;
747
756
  /** On change callback. */
@@ -949,6 +958,8 @@ export interface PopoverProps extends GenericProps {
949
958
  isOpen: boolean;
950
959
  /** Offset placement relative to anchor. */
951
960
  offset?: Offset;
961
+ /** Reference to the parent element that triggered the popover (will get back focus on close or else fallback on the anchor element). */
962
+ parentElement?: RefObject<HTMLElement>;
952
963
  /** Placement relative to anchor. */
953
964
  placement?: Placement;
954
965
  /** Whether the popover should be rendered into a DOM node that exists outside the DOM hierarchy of the parent component. */
@@ -1122,6 +1133,41 @@ export interface FlexBoxProps extends GenericProps {
1122
1133
  * @return React element.
1123
1134
  */
1124
1135
  export declare const FlexBox: Comp<FlexBoxProps, HTMLDivElement>;
1136
+ export interface GenericBlockProps extends FlexBoxProps {
1137
+ /** Component to use as visual element. */
1138
+ figure?: ReactNode;
1139
+ /** Actions to set after the main content. */
1140
+ actions?: ReactNode;
1141
+ /** Main content to display */
1142
+ children: ReactNode;
1143
+ /** Orientation of the 3 sections */
1144
+ orientation?: FlexBoxProps["orientation"];
1145
+ /** Horizontal alignment. */
1146
+ hAlign?: FlexBoxProps["hAlign"];
1147
+ /** Vertical alignment. */
1148
+ vAlign?: FlexBoxProps["vAlign"];
1149
+ /**
1150
+ * The props to forward to the content.
1151
+ * By default, the content will have the same alignment as wrapper.
1152
+ */
1153
+ contentProps?: Omit<FlexBoxProps, "children">;
1154
+ /** props to forward to the actions element. */
1155
+ actionsProps?: Omit<FlexBoxProps, "children">;
1156
+ /** props to forward to the figure element. */
1157
+ figureProps?: Omit<FlexBoxProps, "children">;
1158
+ }
1159
+ /**
1160
+ * The GenericBlock is a layout component made of 3 sections that can be
1161
+ * displayed either horizontally of vertically with the same gap between each section.
1162
+ *
1163
+ * The sections are:
1164
+ * * (Optional) `Figure` => A visual element to display before the main content.
1165
+ * * (Required) `Content` => The main content displayed
1166
+ * * (Optional) `Actions` => One or more actions to set after the element.
1167
+ *
1168
+ * @see https://www.figma.com/file/lzzrQmsfaXRaOyRfoEogPZ/DS%3A-playground?node-id=1%3A4076
1169
+ */
1170
+ export declare const GenericBlock: Comp<GenericBlockProps, HTMLDivElement>;
1125
1171
  export declare type GridGutterSize = Extract<Size, "regular" | "big" | "huge">;
1126
1172
  /**
1127
1173
  * Defines the props of the component.
@@ -1431,12 +1477,12 @@ export declare const Link: Comp<LinkProps, HTMLAnchorElement | HTMLButtonElement
1431
1477
  * Defines the props of the component.
1432
1478
  */
1433
1479
  export interface LinkPreviewProps extends GenericProps {
1434
- /** Description (either a string, or sanitized html). */
1435
- description?: string | {
1436
- __html: string;
1437
- };
1480
+ /** Description. */
1481
+ description?: string;
1438
1482
  /** Link URL. */
1439
1483
  link: string;
1484
+ /** Custom react component for the link (can be used to inject react router Link). */
1485
+ linkAs?: "a" | any;
1440
1486
  /** Props to pass to the link (minus those already set by the LinkPreview props). */
1441
1487
  linkProps?: Omit<LinkProps, "color" | "colorVariant" | "href" | "target">;
1442
1488
  /** Size variant. */
@@ -1447,6 +1493,8 @@ export interface LinkPreviewProps extends GenericProps {
1447
1493
  thumbnailProps?: ThumbnailProps;
1448
1494
  /** Title. */
1449
1495
  title?: string;
1496
+ /** Customize the title heading tag. */
1497
+ titleHeading?: HeadingElement;
1450
1498
  }
1451
1499
  /**
1452
1500
  * LinkPreview component.
@@ -1856,6 +1904,8 @@ export interface CoreSelectProps extends GenericProps {
1856
1904
  helper?: string;
1857
1905
  /** Whether the select should close on click. */
1858
1906
  closeOnClick?: boolean;
1907
+ /** Icon (SVG path). */
1908
+ icon?: string;
1859
1909
  /** Whether the component is disabled or not. */
1860
1910
  isDisabled?: boolean;
1861
1911
  /** Whether the component is required or not. */
@@ -1,51 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`<LinkPreview> Snapshots and structure should render correctly 1`] = `
4
- <div
5
- className="lumx-link-preview lumx-link-preview--size-regular lumx-link-preview--theme-light"
6
- >
7
- <div
8
- className="lumx-link-preview__wrapper"
9
- >
10
- <div
11
- className="lumx-link-preview__container"
12
- >
13
- <div
14
- className="lumx-link-preview__link"
15
- >
16
- <Link
17
- className="lumx-link-preview__link"
18
- color="primary"
19
- colorVariant="N"
20
- target="_blank"
21
- />
22
- </div>
23
- </div>
24
- </div>
25
- </div>
26
- `;
27
-
28
- exports[`<LinkPreview> Snapshots and structure should render correctly 2`] = `
29
- <div
30
- className="lumx-link-preview lumx-link-preview--size-regular lumx-link-preview--theme-light"
31
- >
32
- <div
33
- className="lumx-link-preview__wrapper"
34
- >
35
- <div
36
- className="lumx-link-preview__container"
37
- >
38
- <div
39
- className="lumx-link-preview__link"
40
- >
41
- <Link
42
- className="lumx-link-preview__link"
43
- color="primary"
44
- colorVariant="N"
45
- target="_blank"
46
- />
47
- </div>
48
- </div>
49
- </div>
50
- </div>
51
- `;