@lumx/react 2.2.18 → 2.2.20

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 (100) hide show
  1. package/esm/_internal/ButtonRoot.js.map +1 -1
  2. package/esm/_internal/Checkbox2.js +3 -1
  3. package/esm/_internal/Checkbox2.js.map +1 -1
  4. package/esm/_internal/ClickAwayProvider.js +90 -12
  5. package/esm/_internal/ClickAwayProvider.js.map +1 -1
  6. package/esm/_internal/DatePickerField.js +18 -11
  7. package/esm/_internal/DatePickerField.js.map +1 -1
  8. package/esm/_internal/Dialog2.js +2 -2
  9. package/esm/_internal/Dialog2.js.map +1 -1
  10. package/esm/_internal/GenericBlock.js +90 -0
  11. package/esm/_internal/GenericBlock.js.map +1 -0
  12. package/esm/_internal/Lightbox2.js +2 -2
  13. package/esm/_internal/Lightbox2.js.map +1 -1
  14. package/esm/_internal/LinkPreview.js +22 -12
  15. package/esm/_internal/LinkPreview.js.map +1 -1
  16. package/esm/_internal/Popover2.js +21 -8
  17. package/esm/_internal/Popover2.js.map +1 -1
  18. package/esm/_internal/SelectMultiple.js +16 -4
  19. package/esm/_internal/SelectMultiple.js.map +1 -1
  20. package/esm/_internal/Tooltip2.js +3 -7
  21. package/esm/_internal/Tooltip2.js.map +1 -1
  22. package/esm/_internal/UserBlock.js +9 -2
  23. package/esm/_internal/UserBlock.js.map +1 -1
  24. package/esm/_internal/alert-dialog.js +2 -2
  25. package/esm/_internal/autocomplete.js +2 -1
  26. package/esm/_internal/autocomplete.js.map +1 -1
  27. package/esm/_internal/button.js +2 -1
  28. package/esm/_internal/button.js.map +1 -1
  29. package/esm/_internal/comment-block.js +2 -1
  30. package/esm/_internal/comment-block.js.map +1 -1
  31. package/esm/_internal/date-picker.js +3 -2
  32. package/esm/_internal/date-picker.js.map +1 -1
  33. package/esm/_internal/dialog.js +2 -2
  34. package/esm/_internal/dropdown.js +2 -1
  35. package/esm/_internal/dropdown.js.map +1 -1
  36. package/esm/_internal/expansion-panel.js +1 -1
  37. package/esm/_internal/generic-block.js +12 -0
  38. package/esm/_internal/generic-block.js.map +1 -0
  39. package/esm/_internal/lightbox.js +3 -2
  40. package/esm/_internal/lightbox.js.map +1 -1
  41. package/esm/_internal/popover.js +2 -1
  42. package/esm/_internal/popover.js.map +1 -1
  43. package/esm/_internal/select.js +2 -1
  44. package/esm/_internal/select.js.map +1 -1
  45. package/esm/_internal/side-navigation.js +2 -1
  46. package/esm/_internal/side-navigation.js.map +1 -1
  47. package/esm/_internal/slideshow.js +2 -1
  48. package/esm/_internal/slideshow.js.map +1 -1
  49. package/esm/_internal/text-field.js +2 -1
  50. package/esm/_internal/text-field.js.map +1 -1
  51. package/esm/_internal/tooltip.js +2 -1
  52. package/esm/_internal/tooltip.js.map +1 -1
  53. package/esm/_internal/type.js.map +1 -1
  54. package/esm/_internal/useFocusTrap.js +65 -72
  55. package/esm/_internal/useFocusTrap.js.map +1 -1
  56. package/esm/_internal/user-block.js +1 -0
  57. package/esm/_internal/user-block.js.map +1 -1
  58. package/esm/index.js +4 -2
  59. package/esm/index.js.map +1 -1
  60. package/package.json +5 -5
  61. package/src/components/button/Button.stories.tsx +1 -0
  62. package/src/components/button/ButtonRoot.tsx +4 -4
  63. package/src/components/checkbox/Checkbox.tsx +2 -1
  64. package/src/components/checkbox/__snapshots__/Checkbox.test.tsx.snap +4 -0
  65. package/src/components/date-picker/DatePickerField.tsx +15 -16
  66. package/src/components/date-picker/types.ts +2 -2
  67. package/src/components/dialog/Dialog.stories.tsx +57 -14
  68. package/src/components/dialog/Dialog.tsx +1 -1
  69. package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +160 -91
  70. package/src/components/generic-block/GenericBlock.stories.tsx +149 -0
  71. package/src/components/generic-block/GenericBlock.test.tsx +28 -0
  72. package/src/components/generic-block/GenericBlock.tsx +120 -0
  73. package/src/components/generic-block/__snapshots__/GenericBlock.test.tsx.snap +92 -0
  74. package/src/components/generic-block/index.ts +1 -0
  75. package/src/components/lightbox/Lightbox.tsx +1 -1
  76. package/src/components/link-preview/LinkPreview.test.tsx +50 -55
  77. package/src/components/link-preview/LinkPreview.tsx +43 -16
  78. package/src/components/popover/Popover.tsx +20 -4
  79. package/src/components/select/Select.stories.tsx +2 -0
  80. package/src/components/select/Select.tsx +11 -1
  81. package/src/components/select/SelectMultiple.stories.tsx +2 -0
  82. package/src/components/select/SelectMultiple.tsx +11 -1
  83. package/src/components/select/constants.ts +2 -0
  84. package/src/components/table/__snapshots__/Table.test.tsx.snap +5 -0
  85. package/src/components/tooltip/Tooltip.tsx +2 -5
  86. package/src/components/user-block/UserBlock.stories.tsx +4 -4
  87. package/src/components/user-block/UserBlock.tsx +9 -3
  88. package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +51 -8
  89. package/src/hooks/useBooleanState.tsx +4 -10
  90. package/src/hooks/useCallbackOnEscape.ts +21 -13
  91. package/src/hooks/useFocusTrap.ts +67 -76
  92. package/src/index.ts +1 -0
  93. package/src/stories/generated/Dialog/Demos.stories.tsx +1 -0
  94. package/src/stories/generated/GenericBlock/Demos.stories.tsx +6 -0
  95. package/src/utils/focus/getFirstAndLastFocusable.test.ts +128 -0
  96. package/src/utils/focus/getFirstAndLastFocusable.ts +27 -0
  97. package/src/utils/makeListenerTowerContext.ts +32 -0
  98. package/src/utils/type.ts +3 -0
  99. package/types.d.ts +50 -9
  100. package/src/components/link-preview/__snapshots__/LinkPreview.test.tsx.snap +0 -51
@@ -0,0 +1,12 @@
1
+ import './_rollupPluginBabelHelpers.js';
2
+ import './components.js';
3
+ import 'react';
4
+ import './getRootClassName.js';
5
+ import 'lodash/isBoolean';
6
+ import 'lodash/isEmpty';
7
+ import 'lodash/kebabCase';
8
+ import 'lodash/noop';
9
+ import 'lodash/castArray';
10
+ import './FlexBox.js';
11
+ export { G as GenericBlock } from './GenericBlock.js';
12
+ //# sourceMappingURL=generic-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generic-block.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -9,16 +9,17 @@ import 'lodash/isEmpty';
9
9
  import 'lodash/kebabCase';
10
10
  import 'lodash/noop';
11
11
  import './constants.js';
12
+ import 'lodash/last';
12
13
  import 'lodash/get';
13
14
  import './Popover2.js';
14
15
  import './mergeRefs.js';
15
16
  import './renderLink.js';
16
17
  import './ButtonRoot.js';
17
18
  import './IconButton.js';
18
- import './useFocusTrap.js';
19
- import 'react-dom';
20
19
  import './ClickAwayProvider.js';
21
20
  import 'lodash/pull';
21
+ import './useFocusTrap.js';
22
+ import 'react-dom';
22
23
  import './useDelayedVisibility.js';
23
24
  import './useDisableBodyScroll.js';
24
25
  export { L as Lightbox } from './Lightbox2.js';
@@ -1 +1 @@
1
- {"version":3,"file":"lightbox.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"lightbox.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -6,9 +6,10 @@ import 'lodash/isEmpty';
6
6
  import 'lodash/kebabCase';
7
7
  import 'lodash/noop';
8
8
  import './constants.js';
9
+ import 'lodash/last';
9
10
  export { P as Placement, a as Popover } from './Popover2.js';
10
11
  import './mergeRefs.js';
11
- import 'react-dom';
12
12
  import './ClickAwayProvider.js';
13
13
  import 'lodash/pull';
14
+ import 'react-dom';
14
15
  //# sourceMappingURL=popover.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"popover.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
1
+ {"version":3,"file":"popover.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
@@ -9,6 +9,7 @@ import 'lodash/isEmpty';
9
9
  import 'lodash/kebabCase';
10
10
  import 'lodash/noop';
11
11
  import './constants.js';
12
+ import 'lodash/last';
12
13
  import 'lodash/get';
13
14
  import './type.js';
14
15
  import './Popover2.js';
@@ -18,9 +19,9 @@ import './ButtonRoot.js';
18
19
  import './IconButton.js';
19
20
  import 'lodash/isFunction';
20
21
  import './Chip2.js';
21
- import 'react-dom';
22
22
  import './ClickAwayProvider.js';
23
23
  import 'lodash/pull';
24
+ import 'react-dom';
24
25
  import './List2.js';
25
26
  import './Dropdown2.js';
26
27
  import './InputHelper.js';
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"select.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -9,6 +9,7 @@ import 'lodash/isEmpty';
9
9
  import 'lodash/kebabCase';
10
10
  import 'lodash/noop';
11
11
  import './constants.js';
12
+ import 'lodash/last';
12
13
  import 'lodash/get';
13
14
  import './type.js';
14
15
  import './Popover2.js';
@@ -16,9 +17,9 @@ import './mergeRefs.js';
16
17
  import './renderLink.js';
17
18
  import './ButtonRoot.js';
18
19
  import './IconButton.js';
19
- import 'react-dom';
20
20
  import './ClickAwayProvider.js';
21
21
  import 'lodash/pull';
22
+ import 'react-dom';
22
23
  export { S as SideNavigation, a as SideNavigationItem } from './SideNavigationItem.js';
23
24
  import './Tooltip2.js';
24
25
  //# sourceMappingURL=side-navigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"side-navigation.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"side-navigation.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
@@ -9,6 +9,7 @@ import 'lodash/isEmpty';
9
9
  import 'lodash/kebabCase';
10
10
  import 'lodash/noop';
11
11
  import './constants.js';
12
+ import 'lodash/last';
12
13
  import 'lodash/get';
13
14
  import './Popover2.js';
14
15
  import './mergeRefs.js';
@@ -17,9 +18,9 @@ import './ButtonRoot.js';
17
18
  import './IconButton.js';
18
19
  import 'lodash/isFunction';
19
20
  import 'lodash/range';
20
- import 'react-dom';
21
21
  import './ClickAwayProvider.js';
22
22
  import 'lodash/pull';
23
+ import 'react-dom';
23
24
  export { c as Slides, S as Slideshow, b as SlideshowControls, a as SlideshowItem } from './Slides.js';
24
25
  import 'lodash/uniqueId';
25
26
  import './Tooltip2.js';
@@ -1 +1 @@
1
- {"version":3,"file":"slideshow.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"slideshow.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -9,15 +9,16 @@ import 'lodash/isEmpty';
9
9
  import 'lodash/kebabCase';
10
10
  import 'lodash/noop';
11
11
  import './constants.js';
12
+ import 'lodash/last';
12
13
  import 'lodash/get';
13
14
  import './Popover2.js';
14
15
  import './mergeRefs.js';
15
16
  import './renderLink.js';
16
17
  import './ButtonRoot.js';
17
18
  import './IconButton.js';
18
- import 'react-dom';
19
19
  import './ClickAwayProvider.js';
20
20
  import 'lodash/pull';
21
+ import 'react-dom';
21
22
  import './InputHelper.js';
22
23
  import './InputLabel.js';
23
24
  export { T as TextField } from './TextField.js';
@@ -1 +1 @@
1
- {"version":3,"file":"text-field.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"text-field.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,11 +7,12 @@ import 'lodash/isEmpty';
7
7
  import 'lodash/kebabCase';
8
8
  import 'lodash/noop';
9
9
  import './constants.js';
10
+ import 'lodash/last';
10
11
  import 'lodash/get';
11
12
  import './Popover2.js';
12
13
  import './mergeRefs.js';
13
- import 'react-dom';
14
14
  import './ClickAwayProvider.js';
15
15
  import 'lodash/pull';
16
+ import 'react-dom';
16
17
  export { T as Tooltip } from './Tooltip2.js';
17
18
  //# sourceMappingURL=tooltip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"tooltip.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"type.js","sources":["../../../src/utils/type.ts"],"sourcesContent":["import get from 'lodash/get';\nimport { ReactElement, ReactNode, Ref } from 'react';\n\n/** Get types of the values of a record. */\nexport type ValueOf<T extends Record<any, any>> = T[keyof T];\n\n/**\n * Properties of a component to use to determine it's name.\n * In the order of preference.\n */\nconst NAME_PROPERTIES: string[] = [\n 'type',\n 'type.displayName',\n 'displayName',\n 'name',\n 'type.name',\n 'props.mdxType',\n '_reactInternalFiber.elementType.name',\n];\n\n/** LumX Component Type. */\nexport type Comp<P, T = HTMLElement> = {\n (props: P & { ref?: Ref<T> }): ReactElement | null;\n /** React component type. */\n readonly $$typeof: symbol;\n /** Component default props. */\n defaultProps?: Partial<P>;\n /** Component name. */\n displayName?: string;\n /** Component base class name. */\n className?: string;\n};\n\n/**\n * Define a generic props types.\n */\nexport interface GenericProps {\n /**\n * Any prop (particularly any supported prop for a HTML element).\n * E.g. classNames, onClick, disabled, ...\n */\n [propName: string]: any;\n}\n\n/**\n * Callback function type alias (use for readability)\n */\nexport type Callback = () => void;\nexport type Predicate<T> = (t: T) => boolean;\n\n/**\n * Create a predicate function that checks if a ReactNode is a react element from the given component.\n *\n * @param component React function component or the component name\n * @return predicate returning true if value is instance of the component\n */\nexport const isComponent = <C>(component: Comp<C, any> | string) => (instance: ReactNode): instance is ReactElement => {\n const componentName = typeof component === 'string' ? component : component.displayName;\n\n return (\n !!get(instance, '$$typeof') &&\n NAME_PROPERTIES.some((nameProperty: string): boolean => get(instance, nameProperty) === componentName)\n );\n};\n\n/**\n * JS falsy values.\n * (excluding `NaN` as it can't be distinguished from `number`)\n */\nexport type Falsy = false | undefined | null | 0 | '';\n"],"names":["NAME_PROPERTIES","isComponent","component","instance","componentName","displayName","get","some","nameProperty"],"mappings":";;AAMA;;;;AAIA,IAAMA,eAAyB,GAAG,CAC9B,MAD8B,EAE9B,kBAF8B,EAG9B,aAH8B,EAI9B,MAJ8B,EAK9B,WAL8B,EAM9B,eAN8B,EAO9B,sCAP8B,CAAlC;AAUA;;AA8BA;;;;;;IAMaC,WAAW,GAAG,SAAdA,WAAc,CAAIC,SAAJ;AAAA,SAAyC,UAACC,QAAD,EAAmD;AACnH,QAAMC,aAAa,GAAG,OAAOF,SAAP,KAAqB,QAArB,GAAgCA,SAAhC,GAA4CA,SAAS,CAACG,WAA5E;AAEA,WACI,CAAC,CAACC,GAAG,CAACH,QAAD,EAAW,UAAX,CAAL,IACAH,eAAe,CAACO,IAAhB,CAAqB,UAACC,YAAD;AAAA,aAAmCF,GAAG,CAACH,QAAD,EAAWK,YAAX,CAAH,KAAgCJ,aAAnE;AAAA,KAArB,CAFJ;AAIH,GAP0B;AAAA;AAS3B;;;;;;;"}
1
+ {"version":3,"file":"type.js","sources":["../../../src/utils/type.ts"],"sourcesContent":["import get from 'lodash/get';\nimport { ReactElement, ReactNode, Ref } from 'react';\n\n/** Get types of the values of a record. */\nexport type ValueOf<T extends Record<any, any>> = T[keyof T];\n\n/**\n * Properties of a component to use to determine it's name.\n * In the order of preference.\n */\nconst NAME_PROPERTIES: string[] = [\n 'type',\n 'type.displayName',\n 'displayName',\n 'name',\n 'type.name',\n 'props.mdxType',\n '_reactInternalFiber.elementType.name',\n];\n\n/** LumX Component Type. */\nexport type Comp<P, T = HTMLElement> = {\n (props: P & { ref?: Ref<T> }): ReactElement | null;\n /** React component type. */\n readonly $$typeof: symbol;\n /** Component default props. */\n defaultProps?: Partial<P>;\n /** Component name. */\n displayName?: string;\n /** Component base class name. */\n className?: string;\n};\n\n/** Union type of all heading elements */\nexport type HeadingElement = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n\n/**\n * Define a generic props types.\n */\nexport interface GenericProps {\n /**\n * Any prop (particularly any supported prop for a HTML element).\n * E.g. classNames, onClick, disabled, ...\n */\n [propName: string]: any;\n}\n\n/**\n * Callback function type alias (use for readability)\n */\nexport type Callback = () => void;\nexport type Predicate<T> = (t: T) => boolean;\n\n/**\n * Create a predicate function that checks if a ReactNode is a react element from the given component.\n *\n * @param component React function component or the component name\n * @return predicate returning true if value is instance of the component\n */\nexport const isComponent = <C>(component: Comp<C, any> | string) => (instance: ReactNode): instance is ReactElement => {\n const componentName = typeof component === 'string' ? component : component.displayName;\n\n return (\n !!get(instance, '$$typeof') &&\n NAME_PROPERTIES.some((nameProperty: string): boolean => get(instance, nameProperty) === componentName)\n );\n};\n\n/**\n * JS falsy values.\n * (excluding `NaN` as it can't be distinguished from `number`)\n */\nexport type Falsy = false | undefined | null | 0 | '';\n"],"names":["NAME_PROPERTIES","isComponent","component","instance","componentName","displayName","get","some","nameProperty"],"mappings":";;AAMA;;;;AAIA,IAAMA,eAAyB,GAAG,CAC9B,MAD8B,EAE9B,kBAF8B,EAG9B,aAH8B,EAI9B,MAJ8B,EAK9B,WAL8B,EAM9B,eAN8B,EAO9B,sCAP8B,CAAlC;AAUA;;AAiCA;;;;;;IAMaC,WAAW,GAAG,SAAdA,WAAc,CAAIC,SAAJ;AAAA,SAAyC,UAACC,QAAD,EAAmD;AACnH,QAAMC,aAAa,GAAG,OAAOF,SAAP,KAAqB,QAArB,GAAgCA,SAAhC,GAA4CA,SAAS,CAACG,WAA5E;AAEA,WACI,CAAC,CAACC,GAAG,CAACH,QAAD,EAAW,UAAX,CAAL,IACAH,eAAe,CAACO,IAAhB,CAAqB,UAACC,YAAD;AAAA,aAAmCF,GAAG,CAACH,QAAD,EAAWK,YAAX,CAAH,KAAgCJ,aAAnE;AAAA,KAArB,CAFJ;AAIH,GAP0B;AAAA;AAS3B;;;;;;;"}
@@ -1,92 +1,85 @@
1
1
  import { useEffect } from 'react';
2
2
  import { D as DOCUMENT } from './constants.js';
3
+ import { g as getFirstAndLastFocusable, m as makeListenerTowerContext } from './ClickAwayProvider.js';
3
4
 
4
- /** CSS selector listing all tabbable elements. */
5
-
6
- var TABBABLE_ELEMENTS_SELECTOR = "a[href]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\nbutton:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ntextarea:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"text\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"radio\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"checkbox\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\n[tabindex]:not([tabindex=\"-1\"], [disabled], [aria-disabled])";
5
+ var FOCUS_TRAPS = makeListenerTowerContext();
7
6
  /**
8
- * Get first and last elements focusable in an element.
7
+ * Trap 'Tab' focus switch inside the `focusZoneElement`.
9
8
  *
10
- * @param parentElement The element in which to search focusable elements.
11
- * @return first and last focusable elements
12
- */
13
-
14
- function getFocusable(parentElement) {
15
- var focusableElements = parentElement.querySelectorAll(TABBABLE_ELEMENTS_SELECTOR);
16
-
17
- if (focusableElements.length <= 0) {
18
- return {};
19
- }
20
-
21
- var first = focusableElements[0];
22
- var last = focusableElements[focusableElements.length - 1];
23
- return {
24
- first: first,
25
- last: last
26
- };
27
- }
28
- /**
29
- * Add a key down event handler to the given root element (document.body by default) to trap the move of focus
30
- * (TAB and SHIFT-TAB keys) inside the given focusZoneElement.
31
- * Will focus the given focus element when activating the focus trap.
9
+ * If multiple focus trap are activated, only the last one is maintained and when a focus trap closes, the previous one
10
+ * gets activated again.
32
11
  *
33
12
  * @param focusZoneElement The element in which to trap the focus.
34
- * @param focusElement The element to focus when the focus trap is activated.
35
- * @param rootElement The element on which the key down event will be placed.
13
+ * @param focusElement The element to focus when the focus trap is activated (otherwise the first focusable element
14
+ * will be focused).
36
15
  */
37
16
 
38
-
39
17
  function useFocusTrap(focusZoneElement, focusElement) {
40
- var rootElement = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DOCUMENT === null || DOCUMENT === void 0 ? void 0 : DOCUMENT.body;
41
18
  useEffect(function () {
42
- if (rootElement && focusZoneElement) {
43
- var _ref;
19
+ // Body element can be undefined in SSR context.
20
+ var rootElement = DOCUMENT === null || DOCUMENT === void 0 ? void 0 : DOCUMENT.body;
21
+
22
+ if (!rootElement || !focusZoneElement) {
23
+ return undefined;
24
+ } // Trap 'Tab' key down focus switch into the focus zone.
25
+
44
26
 
45
- (_ref = document.activeElement) === null || _ref === void 0 ? void 0 : _ref.blur();
27
+ var trapTabFocusInFocusZone = function trapTabFocusInFocusZone(evt) {
28
+ var key = evt.key;
46
29
 
47
- if (focusElement) {
48
- focusElement.focus();
30
+ if (key !== 'Tab') {
31
+ return;
49
32
  }
50
33
 
51
- var onKeyDown = function onKeyDown(evt) {
52
- var key = evt.key;
53
-
54
- if (key !== 'Tab') {
55
- return;
56
- }
57
-
58
- var focusable = getFocusable(focusZoneElement); // Prevent focus switch if no focusable available.
59
-
60
- if (!focusable.first) {
61
- evt.preventDefault();
62
- return;
63
- }
64
-
65
- if ( // No previous focus
66
- !document.activeElement || // Previous focus is at the end of the focus zone.
67
- !evt.shiftKey && document.activeElement === focusable.last || // Previous focus is outside the focus zone
68
- !focusZoneElement.contains(document.activeElement)) {
69
- focusable.first.focus();
70
- evt.preventDefault();
71
- return;
72
- }
73
-
74
- if ( // Focus order reversed
75
- evt.shiftKey && // Previous focus is at the start of the focus zone.
76
- document.activeElement === focusable.first) {
77
- focusable.last.focus();
78
- evt.preventDefault();
79
- }
80
- };
81
-
82
- rootElement.addEventListener('keydown', onKeyDown);
83
- return function () {
84
- return rootElement.removeEventListener('keydown', onKeyDown);
85
- };
34
+ var focusable = getFirstAndLastFocusable(focusZoneElement); // Prevent focus switch if no focusable available.
35
+
36
+ if (!focusable.first) {
37
+ evt.preventDefault();
38
+ return;
39
+ }
40
+
41
+ if ( // No previous focus
42
+ !document.activeElement || // Previous focus is at the end of the focus zone.
43
+ !evt.shiftKey && document.activeElement === focusable.last || // Previous focus is outside the focus zone
44
+ !focusZoneElement.contains(document.activeElement)) {
45
+ focusable.first.focus();
46
+ evt.preventDefault();
47
+ return;
48
+ }
49
+
50
+ if ( // Focus order reversed
51
+ evt.shiftKey && // Previous focus is at the start of the focus zone.
52
+ document.activeElement === focusable.first) {
53
+ focusable.last.focus();
54
+ evt.preventDefault();
55
+ }
56
+ };
57
+
58
+ var focusTrap = {
59
+ enable: function enable() {
60
+ return rootElement.addEventListener('keydown', trapTabFocusInFocusZone);
61
+ },
62
+ disable: function disable() {
63
+ return rootElement.removeEventListener('keydown', trapTabFocusInFocusZone);
64
+ }
65
+ }; // SETUP:
66
+
67
+ if (focusElement && focusZoneElement.contains(focusElement)) {
68
+ // Focus the given element.
69
+ focusElement.focus();
70
+ } else {
71
+ var _getFirstAndLastFocus;
72
+
73
+ // Focus the first focusable element in the zone.
74
+ (_getFirstAndLastFocus = getFirstAndLastFocusable(focusZoneElement).first) === null || _getFirstAndLastFocus === void 0 ? void 0 : _getFirstAndLastFocus.focus();
86
75
  }
87
76
 
88
- return undefined;
89
- }, [focusElement, focusZoneElement, rootElement]);
77
+ FOCUS_TRAPS.register(focusTrap); // TEARDOWN:
78
+
79
+ return function () {
80
+ return FOCUS_TRAPS.unregister(focusTrap);
81
+ };
82
+ }, [focusElement, focusZoneElement]);
90
83
  }
91
84
 
92
85
  export { useFocusTrap as u };
@@ -1 +1 @@
1
- {"version":3,"file":"useFocusTrap.js","sources":["../../../src/hooks/useFocusTrap.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { DOCUMENT } from '@lumx/react/constants';\n\n/** CSS selector listing all tabbable elements. */\nconst TABBABLE_ELEMENTS_SELECTOR = `a[href]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\nbutton:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ntextarea:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"text\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"radio\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\ninput[type=\"checkbox\"]:not([tabindex=\"-1\"], [disabled], [aria-disabled]),\n[tabindex]:not([tabindex=\"-1\"], [disabled], [aria-disabled])`;\n\n/**\n * Get first and last elements focusable in an element.\n *\n * @param parentElement The element in which to search focusable elements.\n * @return first and last focusable elements\n */\nfunction getFocusable(parentElement: HTMLElement) {\n const focusableElements = parentElement.querySelectorAll<HTMLElement>(TABBABLE_ELEMENTS_SELECTOR);\n\n if (focusableElements.length <= 0) {\n return {};\n }\n\n const first = focusableElements[0];\n const last = focusableElements[focusableElements.length - 1];\n return { first, last };\n}\n\n/**\n * Add a key down event handler to the given root element (document.body by default) to trap the move of focus\n * (TAB and SHIFT-TAB keys) inside the given focusZoneElement.\n * Will focus the given focus element when activating the focus trap.\n *\n * @param focusZoneElement The element in which to trap the focus.\n * @param focusElement The element to focus when the focus trap is activated.\n * @param rootElement The element on which the key down event will be placed.\n */\nexport function useFocusTrap(\n focusZoneElement: HTMLElement | null,\n focusElement?: HTMLElement | null,\n rootElement = DOCUMENT?.body,\n): void {\n useEffect(() => {\n if (rootElement && focusZoneElement) {\n (document.activeElement as HTMLElement)?.blur();\n if (focusElement) {\n focusElement.focus();\n }\n\n const onKeyDown = (evt: KeyboardEvent) => {\n const { key } = evt;\n if (key !== 'Tab') {\n return;\n }\n const focusable = getFocusable(focusZoneElement);\n\n // Prevent focus switch if no focusable available.\n if (!focusable.first) {\n evt.preventDefault();\n return;\n }\n\n if (\n // No previous focus\n !document.activeElement ||\n // Previous focus is at the end of the focus zone.\n (!evt.shiftKey && document.activeElement === focusable.last) ||\n // Previous focus is outside the focus zone\n !focusZoneElement.contains(document.activeElement)\n ) {\n focusable.first.focus();\n evt.preventDefault();\n return;\n }\n\n if (\n // Focus order reversed\n evt.shiftKey &&\n // Previous focus is at the start of the focus zone.\n document.activeElement === focusable.first\n ) {\n focusable.last.focus();\n evt.preventDefault();\n }\n };\n rootElement.addEventListener('keydown', onKeyDown);\n return () => rootElement.removeEventListener('keydown', onKeyDown);\n }\n return undefined;\n }, [focusElement, focusZoneElement, rootElement]);\n}\n"],"names":["TABBABLE_ELEMENTS_SELECTOR","getFocusable","parentElement","focusableElements","querySelectorAll","length","first","last","useFocusTrap","focusZoneElement","focusElement","rootElement","DOCUMENT","body","useEffect","document","activeElement","blur","focus","onKeyDown","evt","key","focusable","preventDefault","shiftKey","contains","addEventListener","removeEventListener","undefined"],"mappings":";;;AAIA;;AACA,IAAMA,0BAA0B,meAAhC;AAQA;;;;;;;AAMA,SAASC,YAAT,CAAsBC,aAAtB,EAAkD;AAC9C,MAAMC,iBAAiB,GAAGD,aAAa,CAACE,gBAAd,CAA4CJ,0BAA5C,CAA1B;;AAEA,MAAIG,iBAAiB,CAACE,MAAlB,IAA4B,CAAhC,EAAmC;AAC/B,WAAO,EAAP;AACH;;AAED,MAAMC,KAAK,GAAGH,iBAAiB,CAAC,CAAD,CAA/B;AACA,MAAMI,IAAI,GAAGJ,iBAAiB,CAACA,iBAAiB,CAACE,MAAlB,GAA2B,CAA5B,CAA9B;AACA,SAAO;AAAEC,IAAAA,KAAK,EAALA,KAAF;AAASC,IAAAA,IAAI,EAAJA;AAAT,GAAP;AACH;AAED;;;;;;;;;;;AASO,SAASC,YAAT,CACHC,gBADG,EAEHC,YAFG,EAIC;AAAA,MADJC,WACI,uEADUC,QACV,aADUA,QACV,uBADUA,QAAQ,CAAEC,IACpB;AACJC,EAAAA,SAAS,CAAC,YAAM;AACZ,QAAIH,WAAW,IAAIF,gBAAnB,EAAqC;AAAA;;AACjC,cAACM,QAAQ,CAACC,aAAV,8CAAyCC,IAAzC;;AACA,UAAIP,YAAJ,EAAkB;AACdA,QAAAA,YAAY,CAACQ,KAAb;AACH;;AAED,UAAMC,SAAS,GAAG,SAAZA,SAAY,CAACC,GAAD,EAAwB;AAAA,YAC9BC,GAD8B,GACtBD,GADsB,CAC9BC,GAD8B;;AAEtC,YAAIA,GAAG,KAAK,KAAZ,EAAmB;AACf;AACH;;AACD,YAAMC,SAAS,GAAGrB,YAAY,CAACQ,gBAAD,CAA9B,CALsC;;AAQtC,YAAI,CAACa,SAAS,CAAChB,KAAf,EAAsB;AAClBc,UAAAA,GAAG,CAACG,cAAJ;AACA;AACH;;AAED;AAEI,SAACR,QAAQ,CAACC,aAAV;AAEC,SAACI,GAAG,CAACI,QAAL,IAAiBT,QAAQ,CAACC,aAAT,KAA2BM,SAAS,CAACf,IAFvD;AAIA,SAACE,gBAAgB,CAACgB,QAAjB,CAA0BV,QAAQ,CAACC,aAAnC,CANL,EAOE;AACEM,UAAAA,SAAS,CAAChB,KAAV,CAAgBY,KAAhB;AACAE,UAAAA,GAAG,CAACG,cAAJ;AACA;AACH;;AAED;AAEIH,QAAAA,GAAG,CAACI,QAAJ;AAEAT,QAAAA,QAAQ,CAACC,aAAT,KAA2BM,SAAS,CAAChB,KAJzC,EAKE;AACEgB,UAAAA,SAAS,CAACf,IAAV,CAAeW,KAAf;AACAE,UAAAA,GAAG,CAACG,cAAJ;AACH;AACJ,OAnCD;;AAoCAZ,MAAAA,WAAW,CAACe,gBAAZ,CAA6B,SAA7B,EAAwCP,SAAxC;AACA,aAAO;AAAA,eAAMR,WAAW,CAACgB,mBAAZ,CAAgC,SAAhC,EAA2CR,SAA3C,CAAN;AAAA,OAAP;AACH;;AACD,WAAOS,SAAP;AACH,GA/CQ,EA+CN,CAAClB,YAAD,EAAeD,gBAAf,EAAiCE,WAAjC,CA/CM,CAAT;AAgDH;;;;"}
1
+ {"version":3,"file":"useFocusTrap.js","sources":["../../../src/hooks/useFocusTrap.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { DOCUMENT } from '@lumx/react/constants';\nimport { getFirstAndLastFocusable } from '@lumx/react/utils/focus/getFirstAndLastFocusable';\nimport { Falsy } from '@lumx/react/utils';\nimport { Listener, makeListenerTowerContext } from '@lumx/react/utils/makeListenerTowerContext';\n\nconst FOCUS_TRAPS = makeListenerTowerContext();\n\n/**\n * Trap 'Tab' focus switch inside the `focusZoneElement`.\n *\n * If multiple focus trap are activated, only the last one is maintained and when a focus trap closes, the previous one\n * gets activated again.\n *\n * @param focusZoneElement The element in which to trap the focus.\n * @param focusElement The element to focus when the focus trap is activated (otherwise the first focusable element\n * will be focused).\n */\nexport function useFocusTrap(focusZoneElement: HTMLElement | Falsy, focusElement?: HTMLElement | null): void {\n useEffect(() => {\n // Body element can be undefined in SSR context.\n const rootElement = DOCUMENT?.body;\n\n if (!rootElement || !focusZoneElement) {\n return undefined;\n }\n\n // Trap 'Tab' key down focus switch into the focus zone.\n const trapTabFocusInFocusZone = (evt: KeyboardEvent) => {\n const { key } = evt;\n if (key !== 'Tab') {\n return;\n }\n const focusable = getFirstAndLastFocusable(focusZoneElement);\n\n // Prevent focus switch if no focusable available.\n if (!focusable.first) {\n evt.preventDefault();\n return;\n }\n\n if (\n // No previous focus\n !document.activeElement ||\n // Previous focus is at the end of the focus zone.\n (!evt.shiftKey && document.activeElement === focusable.last) ||\n // Previous focus is outside the focus zone\n !focusZoneElement.contains(document.activeElement)\n ) {\n focusable.first.focus();\n evt.preventDefault();\n return;\n }\n\n if (\n // Focus order reversed\n evt.shiftKey &&\n // Previous focus is at the start of the focus zone.\n document.activeElement === focusable.first\n ) {\n focusable.last.focus();\n evt.preventDefault();\n }\n };\n\n const focusTrap: Listener = {\n enable: () => rootElement.addEventListener('keydown', trapTabFocusInFocusZone),\n disable: () => rootElement.removeEventListener('keydown', trapTabFocusInFocusZone),\n };\n\n // SETUP:\n if (focusElement && focusZoneElement.contains(focusElement)) {\n // Focus the given element.\n focusElement.focus();\n } else {\n // Focus the first focusable element in the zone.\n getFirstAndLastFocusable(focusZoneElement).first?.focus();\n }\n FOCUS_TRAPS.register(focusTrap);\n\n // TEARDOWN:\n return () => FOCUS_TRAPS.unregister(focusTrap);\n }, [focusElement, focusZoneElement]);\n}\n"],"names":["FOCUS_TRAPS","makeListenerTowerContext","useFocusTrap","focusZoneElement","focusElement","useEffect","rootElement","DOCUMENT","body","undefined","trapTabFocusInFocusZone","evt","key","focusable","getFirstAndLastFocusable","first","preventDefault","document","activeElement","shiftKey","last","contains","focus","focusTrap","enable","addEventListener","disable","removeEventListener","register","unregister"],"mappings":";;;;AAOA,IAAMA,WAAW,GAAGC,wBAAwB,EAA5C;AAEA;;;;;;;;;;;AAUO,SAASC,YAAT,CAAsBC,gBAAtB,EAA6DC,YAA7D,EAAsG;AACzGC,EAAAA,SAAS,CAAC,YAAM;AACZ;AACA,QAAMC,WAAW,GAAGC,QAAH,aAAGA,QAAH,uBAAGA,QAAQ,CAAEC,IAA9B;;AAEA,QAAI,CAACF,WAAD,IAAgB,CAACH,gBAArB,EAAuC;AACnC,aAAOM,SAAP;AACH,KANW;;;AASZ,QAAMC,uBAAuB,GAAG,SAA1BA,uBAA0B,CAACC,GAAD,EAAwB;AAAA,UAC5CC,GAD4C,GACpCD,GADoC,CAC5CC,GAD4C;;AAEpD,UAAIA,GAAG,KAAK,KAAZ,EAAmB;AACf;AACH;;AACD,UAAMC,SAAS,GAAGC,wBAAwB,CAACX,gBAAD,CAA1C,CALoD;;AAQpD,UAAI,CAACU,SAAS,CAACE,KAAf,EAAsB;AAClBJ,QAAAA,GAAG,CAACK,cAAJ;AACA;AACH;;AAED;AAEI,OAACC,QAAQ,CAACC,aAAV;AAEC,OAACP,GAAG,CAACQ,QAAL,IAAiBF,QAAQ,CAACC,aAAT,KAA2BL,SAAS,CAACO,IAFvD;AAIA,OAACjB,gBAAgB,CAACkB,QAAjB,CAA0BJ,QAAQ,CAACC,aAAnC,CANL,EAOE;AACEL,QAAAA,SAAS,CAACE,KAAV,CAAgBO,KAAhB;AACAX,QAAAA,GAAG,CAACK,cAAJ;AACA;AACH;;AAED;AAEIL,MAAAA,GAAG,CAACQ,QAAJ;AAEAF,MAAAA,QAAQ,CAACC,aAAT,KAA2BL,SAAS,CAACE,KAJzC,EAKE;AACEF,QAAAA,SAAS,CAACO,IAAV,CAAeE,KAAf;AACAX,QAAAA,GAAG,CAACK,cAAJ;AACH;AACJ,KAnCD;;AAqCA,QAAMO,SAAmB,GAAG;AACxBC,MAAAA,MAAM,EAAE;AAAA,eAAMlB,WAAW,CAACmB,gBAAZ,CAA6B,SAA7B,EAAwCf,uBAAxC,CAAN;AAAA,OADgB;AAExBgB,MAAAA,OAAO,EAAE;AAAA,eAAMpB,WAAW,CAACqB,mBAAZ,CAAgC,SAAhC,EAA2CjB,uBAA3C,CAAN;AAAA;AAFe,KAA5B,CA9CY;;AAoDZ,QAAIN,YAAY,IAAID,gBAAgB,CAACkB,QAAjB,CAA0BjB,YAA1B,CAApB,EAA6D;AACzD;AACAA,MAAAA,YAAY,CAACkB,KAAb;AACH,KAHD,MAGO;AAAA;;AACH;AACA,+BAAAR,wBAAwB,CAACX,gBAAD,CAAxB,CAA2CY,KAA3C,gFAAkDO,KAAlD;AACH;;AACDtB,IAAAA,WAAW,CAAC4B,QAAZ,CAAqBL,SAArB,EA3DY;;AA8DZ,WAAO;AAAA,aAAMvB,WAAW,CAAC6B,UAAZ,CAAuBN,SAAvB,CAAN;AAAA,KAAP;AACH,GA/DQ,EA+DN,CAACnB,YAAD,EAAeD,gBAAf,CA/DM,CAAT;AAgEH;;;;"}
@@ -12,5 +12,6 @@ import './Avatar2.js';
12
12
  import './renderLink.js';
13
13
  import './Link2.js';
14
14
  import './Thumbnail2.js';
15
+ import 'lodash/set';
15
16
  export { U as UserBlock } from './UserBlock.js';
16
17
  //# sourceMappingURL=user-block.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-block.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"user-block.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
package/esm/index.js CHANGED
@@ -37,11 +37,11 @@ import 'moment';
37
37
  export { D as DatePicker, a as DatePickerControlled, b as DatePickerField } from './_internal/DatePickerField.js';
38
38
  import 'lodash/range';
39
39
  import 'moment-range';
40
+ import './_internal/ClickAwayProvider.js';
41
+ import 'lodash/pull';
40
42
  import './_internal/useFocusTrap.js';
41
43
  import 'react-dom';
42
- import './_internal/ClickAwayProvider.js';
43
44
  export { D as Dialog } from './_internal/Dialog2.js';
44
- import 'lodash/pull';
45
45
  import './_internal/useDelayedVisibility.js';
46
46
  import './_internal/useDisableBodyScroll.js';
47
47
  export { D as DEFAULT_PROPS, a as Divider } from './_internal/Divider2.js';
@@ -52,6 +52,7 @@ export { E as ExpansionPanel } from './_internal/ExpansionPanel.js';
52
52
  export { F as Flag } from './_internal/Flag2.js';
53
53
  import 'lodash/castArray';
54
54
  export { F as FlexBox } from './_internal/FlexBox.js';
55
+ export { G as GenericBlock } from './_internal/GenericBlock.js';
55
56
  export { G as Grid, a as GridItem } from './_internal/GridItem.js';
56
57
  import 'lodash/isObject';
57
58
  export { a as ImageBlock, I as ImageBlockCaptionPosition } from './_internal/ImageBlock.js';
@@ -85,5 +86,6 @@ export { T as ThumbnailAspectRatio, a as ThumbnailVariant } from './_internal/ty
85
86
  export { T as Toolbar } from './_internal/Toolbar2.js';
86
87
  export { T as Tooltip } from './_internal/Tooltip2.js';
87
88
  export { a as Uploader, U as UploaderVariant } from './_internal/Uploader2.js';
89
+ import 'lodash/set';
88
90
  export { U as UserBlock } from './_internal/UserBlock.js';
89
91
  //# sourceMappingURL=index.js.map
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -7,8 +7,8 @@
7
7
  },
8
8
  "dependencies": {
9
9
  "@juggle/resize-observer": "^3.2.0",
10
- "@lumx/core": "^2.2.18",
11
- "@lumx/icons": "^2.2.18",
10
+ "@lumx/core": "^2.2.20",
11
+ "@lumx/icons": "^2.2.20",
12
12
  "@popperjs/core": "^2.5.4",
13
13
  "body-scroll-lock": "^3.1.5",
14
14
  "classnames": "^2.2.6",
@@ -72,7 +72,7 @@
72
72
  "rollup-plugin-typescript-paths": "^1.2.2",
73
73
  "test-data-bot": "^0.8.0",
74
74
  "ts-jest": "^26.2.0",
75
- "tsconfig-paths-webpack-plugin": "^3.2.0",
75
+ "tsconfig-paths-webpack-plugin": "^3.3.0",
76
76
  "typescript": "^4.1.2",
77
77
  "yargs": "^15.4.1",
78
78
  "yarn": "^1.19.1"
@@ -120,6 +120,6 @@
120
120
  "build:storybook": "cd storybook && ./build"
121
121
  },
122
122
  "sideEffects": false,
123
- "version": "2.2.18",
124
- "gitHead": "76dbe9453429551c6332560fc8cdb7abab8eeb04"
123
+ "version": "2.2.20",
124
+ "gitHead": "6eeb06197c8558c38c9af1bfd2ec920b221aa8b3"
125
125
  }
@@ -13,6 +13,7 @@ const DEFAULT_PROPS = Button.defaultProps as any;
13
13
  export const SimpleButton = ({ theme }: any) => {
14
14
  return (
15
15
  <Button
16
+ aria-pressed={boolean('isSelected', Boolean(DEFAULT_PROPS.isSelected))}
16
17
  emphasis={emphasis('Emphasis', DEFAULT_PROPS.emphasis)}
17
18
  theme={theme}
18
19
  rightIcon={select('Right icon', { none: undefined, mdiSend }, undefined)}
@@ -1,4 +1,4 @@
1
- import React, { ButtonHTMLAttributes, DetailedHTMLProps, forwardRef, RefObject } from 'react';
1
+ import React, { AriaAttributes, ButtonHTMLAttributes, DetailedHTMLProps, forwardRef, RefObject } from 'react';
2
2
 
3
3
  import isEmpty from 'lodash/isEmpty';
4
4
 
@@ -16,9 +16,9 @@ type HTMLButtonProps = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>
16
16
  */
17
17
  export type ButtonSize = Extract<Size, 's' | 'm'>;
18
18
 
19
- export interface BaseButtonProps extends GenericProps {
20
- /** ARIA button label. */
21
- ['aria-label']?: string;
19
+ export interface BaseButtonProps
20
+ extends GenericProps,
21
+ Pick<AriaAttributes, 'aria-expanded' | 'aria-haspopup' | 'aria-pressed' | 'aria-label'> {
22
22
  /** Color variant. */
23
23
  color?: Color;
24
24
  /** Emphasis variant. */
@@ -112,6 +112,7 @@ export const Checkbox: Comp<CheckboxProps, HTMLDivElement> = forwardRef((props,
112
112
  value={value}
113
113
  checked={isChecked}
114
114
  onChange={handleChange}
115
+ aria-describedby={helper ? `${inputId}-helper` : undefined}
115
116
  {...inputProps}
116
117
  />
117
118
 
@@ -131,7 +132,7 @@ export const Checkbox: Comp<CheckboxProps, HTMLDivElement> = forwardRef((props,
131
132
  </InputLabel>
132
133
  )}
133
134
  {helper && (
134
- <InputHelper className={`${CLASSNAME}__helper`} theme={theme}>
135
+ <InputHelper id={`${inputId}-helper`} className={`${CLASSNAME}__helper`} theme={theme}>
135
136
  {helper}
136
137
  </InputHelper>
137
138
  )}
@@ -8,6 +8,7 @@ exports[`<Checkbox> Props should use the given props 1`] = `
8
8
  className="lumx-checkbox__input-wrapper"
9
9
  >
10
10
  <input
11
+ aria-describedby="fixedId-helper"
11
12
  className="lumx-checkbox__input-native"
12
13
  id="fixedId"
13
14
  onChange={[Function]}
@@ -41,6 +42,7 @@ exports[`<Checkbox> Props should use the given props 1`] = `
41
42
  </InputLabel>
42
43
  <InputHelper
43
44
  className="lumx-checkbox__helper"
45
+ id="fixedId-helper"
44
46
  kind="info"
45
47
  theme="light"
46
48
  >
@@ -58,6 +60,7 @@ exports[`<Checkbox> Props should use the given props while passing custom props
58
60
  className="lumx-checkbox__input-wrapper"
59
61
  >
60
62
  <input
63
+ aria-describedby="fixedId-helper"
61
64
  aria-labelledby="labelledby-id"
62
65
  className="lumx-checkbox__input-native"
63
66
  id="fixedId"
@@ -92,6 +95,7 @@ exports[`<Checkbox> Props should use the given props while passing custom props
92
95
  </InputLabel>
93
96
  <InputHelper
94
97
  className="lumx-checkbox__helper"
98
+ id="fixedId-helper"
95
99
  kind="info"
96
100
  theme="light"
97
101
  >
@@ -62,7 +62,7 @@ export const DatePickerField: Comp<DatePickerFieldProps, HTMLDivElement> = forwa
62
62
  value,
63
63
  ...forwardedProps
64
64
  } = props;
65
- const wrapperRef = useRef(null);
65
+ const [wrapperElement, setWrapperElement] = useState<HTMLDivElement | null>(null);
66
66
  const anchorRef = useRef(null);
67
67
 
68
68
  const [isOpen, setIsOpen] = useState(false);
@@ -83,8 +83,8 @@ export const DatePickerField: Comp<DatePickerFieldProps, HTMLDivElement> = forwa
83
83
  };
84
84
 
85
85
  // Handle focus trap.
86
- const todayOrSelectedDateRef = useRef<HTMLButtonElement>(null);
87
- useFocusTrap(todayOrSelectedDateRef.current && wrapperRef.current, todayOrSelectedDateRef.current);
86
+ const [todayOrSelectedDate, setTodayOrSelectedDate] = useState<HTMLButtonElement | null>(null);
87
+ useFocusTrap(isOpen && wrapperElement, todayOrSelectedDate);
88
88
 
89
89
  const onTextFieldChange = (textFieldValue: string, textFieldName?: string, event?: SyntheticEvent) => {
90
90
  if (!textFieldValue) {
@@ -121,19 +121,18 @@ export const DatePickerField: Comp<DatePickerFieldProps, HTMLDivElement> = forwa
121
121
  closeOnClickAway
122
122
  closeOnEscape
123
123
  >
124
- <div ref={wrapperRef}>
125
- <DatePicker
126
- locale={locale}
127
- maxDate={maxDate}
128
- minDate={minDate}
129
- value={value}
130
- onChange={onDatePickerChange}
131
- todayOrSelectedDateRef={todayOrSelectedDateRef}
132
- defaultMonth={defaultMonth}
133
- nextButtonProps={nextButtonProps}
134
- previousButtonProps={previousButtonProps}
135
- />
136
- </div>
124
+ <DatePicker
125
+ ref={setWrapperElement}
126
+ locale={locale}
127
+ maxDate={maxDate}
128
+ minDate={minDate}
129
+ value={value}
130
+ onChange={onDatePickerChange}
131
+ todayOrSelectedDateRef={setTodayOrSelectedDate}
132
+ defaultMonth={defaultMonth}
133
+ nextButtonProps={nextButtonProps}
134
+ previousButtonProps={previousButtonProps}
135
+ />
137
136
  </Popover>
138
137
  ) : null}
139
138
  </>
@@ -1,6 +1,6 @@
1
1
  import { IconButtonProps } from '@lumx/react';
2
2
  import { GenericProps } from '@lumx/react/utils';
3
- import { RefObject } from 'react';
3
+ import { Ref } from 'react';
4
4
 
5
5
  /**
6
6
  * Defines the props of the component.
@@ -20,7 +20,7 @@ export interface DatePickerProps extends GenericProps {
20
20
  previousButtonProps: Pick<IconButtonProps, 'label'> &
21
21
  Omit<IconButtonProps, 'label' | 'onClick' | 'icon' | 'emphasis'>;
22
22
  /** Reference to the <button> element corresponding to the current date or the selected date. */
23
- todayOrSelectedDateRef?: RefObject<HTMLButtonElement>;
23
+ todayOrSelectedDateRef?: Ref<HTMLButtonElement>;
24
24
  /** Currently selected date. */
25
25
  value: Date | undefined;
26
26
  /** On change callback. */