@lumx/react 2.2.20-alpha.xss.datatable → 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.
- package/esm/_internal/ClickAwayProvider.js +90 -12
- package/esm/_internal/ClickAwayProvider.js.map +1 -1
- package/esm/_internal/DatePickerField.js +18 -11
- package/esm/_internal/DatePickerField.js.map +1 -1
- package/esm/_internal/Dialog2.js +2 -2
- package/esm/_internal/Dialog2.js.map +1 -1
- package/esm/_internal/GenericBlock.js +90 -0
- package/esm/_internal/GenericBlock.js.map +1 -0
- package/esm/_internal/Lightbox2.js +2 -2
- package/esm/_internal/Lightbox2.js.map +1 -1
- package/esm/_internal/LinkPreview.js +22 -12
- package/esm/_internal/LinkPreview.js.map +1 -1
- package/esm/_internal/Popover2.js +21 -8
- package/esm/_internal/Popover2.js.map +1 -1
- package/esm/_internal/SelectMultiple.js +16 -4
- package/esm/_internal/SelectMultiple.js.map +1 -1
- package/esm/_internal/alert-dialog.js +2 -2
- package/esm/_internal/autocomplete.js +2 -1
- package/esm/_internal/autocomplete.js.map +1 -1
- package/esm/_internal/button.js +2 -1
- package/esm/_internal/button.js.map +1 -1
- package/esm/_internal/comment-block.js +2 -1
- package/esm/_internal/comment-block.js.map +1 -1
- package/esm/_internal/date-picker.js +3 -2
- package/esm/_internal/date-picker.js.map +1 -1
- package/esm/_internal/dialog.js +2 -2
- package/esm/_internal/dropdown.js +2 -1
- package/esm/_internal/dropdown.js.map +1 -1
- package/esm/_internal/expansion-panel.js +1 -1
- package/esm/_internal/generic-block.js +12 -0
- package/esm/_internal/generic-block.js.map +1 -0
- package/esm/_internal/lightbox.js +3 -2
- package/esm/_internal/lightbox.js.map +1 -1
- package/esm/_internal/popover.js +2 -1
- package/esm/_internal/popover.js.map +1 -1
- package/esm/_internal/select.js +2 -1
- package/esm/_internal/select.js.map +1 -1
- package/esm/_internal/side-navigation.js +2 -1
- package/esm/_internal/side-navigation.js.map +1 -1
- package/esm/_internal/slideshow.js +2 -1
- package/esm/_internal/slideshow.js.map +1 -1
- package/esm/_internal/text-field.js +2 -1
- package/esm/_internal/text-field.js.map +1 -1
- package/esm/_internal/tooltip.js +2 -1
- package/esm/_internal/tooltip.js.map +1 -1
- package/esm/_internal/type.js.map +1 -1
- package/esm/_internal/useFocusTrap.js +62 -78
- package/esm/_internal/useFocusTrap.js.map +1 -1
- package/esm/index.js +3 -2
- package/esm/index.js.map +1 -1
- package/package.json +4 -4
- package/src/components/date-picker/DatePickerField.tsx +15 -16
- package/src/components/date-picker/types.ts +2 -2
- package/src/components/dialog/Dialog.stories.tsx +53 -13
- package/src/components/dialog/Dialog.tsx +1 -1
- package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +75 -14
- package/src/components/generic-block/GenericBlock.stories.tsx +149 -0
- package/src/components/generic-block/GenericBlock.test.tsx +28 -0
- package/src/components/generic-block/GenericBlock.tsx +120 -0
- package/src/components/generic-block/__snapshots__/GenericBlock.test.tsx.snap +92 -0
- package/src/components/generic-block/index.ts +1 -0
- package/src/components/lightbox/Lightbox.tsx +1 -1
- package/src/components/link-preview/LinkPreview.test.tsx +50 -55
- package/src/components/link-preview/LinkPreview.tsx +43 -16
- package/src/components/popover/Popover.tsx +20 -4
- package/src/components/select/Select.stories.tsx +2 -0
- package/src/components/select/Select.tsx +11 -1
- package/src/components/select/SelectMultiple.stories.tsx +2 -0
- package/src/components/select/SelectMultiple.tsx +11 -1
- package/src/components/select/constants.ts +2 -0
- package/src/components/table/__snapshots__/Table.test.tsx.snap +5 -0
- package/src/hooks/useCallbackOnEscape.ts +21 -13
- package/src/hooks/useFocusTrap.ts +68 -51
- package/src/index.ts +1 -0
- package/src/stories/generated/GenericBlock/Demos.stories.tsx +6 -0
- package/src/utils/makeListenerTowerContext.ts +32 -0
- package/src/utils/type.ts +3 -0
- package/types.d.ts +48 -5
- package/src/components/link-preview/__snapshots__/LinkPreview.test.tsx.snap +0 -51
|
@@ -1,101 +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
|
-
|
|
5
|
-
var TABBABLE_ELEMENTS_SELECTOR = "a[href], button, textarea, input:not([type=\"hidden\"]), [tabindex]";
|
|
6
|
-
/** CSS selector matching element that are disabled (should not receive focus). */
|
|
7
|
-
|
|
8
|
-
var DISABLED_SELECTOR = "[tabindex=\"-1\"], [disabled]:not([disabled=\"false\"]), [aria-disabled]:not([aria-disabled=\"false\"])";
|
|
9
|
-
|
|
10
|
-
var isNotDisabled = function isNotDisabled(element) {
|
|
11
|
-
return !element.matches(DISABLED_SELECTOR);
|
|
12
|
-
};
|
|
5
|
+
var FOCUS_TRAPS = makeListenerTowerContext();
|
|
13
6
|
/**
|
|
14
|
-
*
|
|
7
|
+
* Trap 'Tab' focus switch inside the `focusZoneElement`.
|
|
8
|
+
*
|
|
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.
|
|
15
11
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* @
|
|
12
|
+
* @param focusZoneElement The element in which to trap the focus.
|
|
13
|
+
* @param focusElement The element to focus when the focus trap is activated (otherwise the first focusable element
|
|
14
|
+
* will be focused).
|
|
18
15
|
*/
|
|
19
16
|
|
|
17
|
+
function useFocusTrap(focusZoneElement, focusElement) {
|
|
18
|
+
useEffect(function () {
|
|
19
|
+
// Body element can be undefined in SSR context.
|
|
20
|
+
var rootElement = DOCUMENT === null || DOCUMENT === void 0 ? void 0 : DOCUMENT.body;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
if (!rootElement || !focusZoneElement) {
|
|
23
|
+
return undefined;
|
|
24
|
+
} // Trap 'Tab' key down focus switch into the focus zone.
|
|
23
25
|
|
|
24
|
-
var first = focusableElements.find(isNotDisabled); // Last non disabled element.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
var trapTabFocusInFocusZone = function trapTabFocusInFocusZone(evt) {
|
|
28
|
+
var key = evt.key;
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
last: last
|
|
32
|
-
};
|
|
33
|
-
}
|
|
30
|
+
if (key !== 'Tab') {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
}
|
|
34
|
+
var focusable = getFirstAndLastFocusable(focusZoneElement); // Prevent focus switch if no focusable available.
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
* @param focusZoneElement The element in which to trap the focus.
|
|
44
|
-
* @param focusElement The element to focus when the focus trap is activated.
|
|
45
|
-
* @param rootElement The element on which the key down event will be placed.
|
|
46
|
-
*/
|
|
36
|
+
if (!focusable.first) {
|
|
37
|
+
evt.preventDefault();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
}
|
|
53
49
|
|
|
54
|
-
(
|
|
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
|
+
};
|
|
55
57
|
|
|
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);
|
|
58
64
|
}
|
|
65
|
+
}; // SETUP:
|
|
66
|
+
|
|
67
|
+
if (focusElement && focusZoneElement.contains(focusElement)) {
|
|
68
|
+
// Focus the given element.
|
|
69
|
+
focusElement.focus();
|
|
70
|
+
} else {
|
|
71
|
+
var _getFirstAndLastFocus;
|
|
59
72
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (key !== 'Tab') {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
var focusable = getFirstAndLastFocusable(focusZoneElement); // Prevent focus switch if no focusable available.
|
|
68
|
-
|
|
69
|
-
if (!focusable.first) {
|
|
70
|
-
evt.preventDefault();
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if ( // No previous focus
|
|
75
|
-
!document.activeElement || // Previous focus is at the end of the focus zone.
|
|
76
|
-
!evt.shiftKey && document.activeElement === focusable.last || // Previous focus is outside the focus zone
|
|
77
|
-
!focusZoneElement.contains(document.activeElement)) {
|
|
78
|
-
focusable.first.focus();
|
|
79
|
-
evt.preventDefault();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if ( // Focus order reversed
|
|
84
|
-
evt.shiftKey && // Previous focus is at the start of the focus zone.
|
|
85
|
-
document.activeElement === focusable.first) {
|
|
86
|
-
focusable.last.focus();
|
|
87
|
-
evt.preventDefault();
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
rootElement.addEventListener('keydown', onKeyDown);
|
|
92
|
-
return function () {
|
|
93
|
-
return rootElement.removeEventListener('keydown', onKeyDown);
|
|
94
|
-
};
|
|
73
|
+
// Focus the first focusable element in the zone.
|
|
74
|
+
(_getFirstAndLastFocus = getFirstAndLastFocusable(focusZoneElement).first) === null || _getFirstAndLastFocus === void 0 ? void 0 : _getFirstAndLastFocus.focus();
|
|
95
75
|
}
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
|
|
77
|
+
FOCUS_TRAPS.register(focusTrap); // TEARDOWN:
|
|
78
|
+
|
|
79
|
+
return function () {
|
|
80
|
+
return FOCUS_TRAPS.unregister(focusTrap);
|
|
81
|
+
};
|
|
82
|
+
}, [focusElement, focusZoneElement]);
|
|
99
83
|
}
|
|
100
84
|
|
|
101
85
|
export { useFocusTrap as u };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocusTrap.js","sources":["../../../src/
|
|
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;;;;"}
|
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';
|
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.20
|
|
11
|
-
"@lumx/icons": "^2.2.20
|
|
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",
|
|
@@ -120,6 +120,6 @@
|
|
|
120
120
|
"build:storybook": "cd storybook && ./build"
|
|
121
121
|
},
|
|
122
122
|
"sideEffects": false,
|
|
123
|
-
"version": "2.2.20
|
|
124
|
-
"gitHead": "
|
|
123
|
+
"version": "2.2.20",
|
|
124
|
+
"gitHead": "6eeb06197c8558c38c9af1bfd2ec920b221aa8b3"
|
|
125
125
|
}
|
|
@@ -62,7 +62,7 @@ export const DatePickerField: Comp<DatePickerFieldProps, HTMLDivElement> = forwa
|
|
|
62
62
|
value,
|
|
63
63
|
...forwardedProps
|
|
64
64
|
} = props;
|
|
65
|
-
const
|
|
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
|
|
87
|
-
useFocusTrap(
|
|
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
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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 {
|
|
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?:
|
|
23
|
+
todayOrSelectedDateRef?: Ref<HTMLButtonElement>;
|
|
24
24
|
/** Currently selected date. */
|
|
25
25
|
value: Date | undefined;
|
|
26
26
|
/** On change callback. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import noop from 'lodash/noop';
|
|
1
2
|
import { mdiClose } from '@lumx/icons';
|
|
2
3
|
import {
|
|
3
4
|
AlertDialog,
|
|
@@ -17,7 +18,8 @@ import {
|
|
|
17
18
|
} from '@lumx/react';
|
|
18
19
|
import { DIALOG_TRANSITION_DURATION } from '@lumx/core/js/constants';
|
|
19
20
|
import { select } from '@storybook/addon-knobs';
|
|
20
|
-
import React, { RefObject, useRef, useState } from 'react';
|
|
21
|
+
import React, { RefObject, useCallback, useRef, useState } from 'react';
|
|
22
|
+
import { useBooleanState } from '@lumx/react/hooks/useBooleanState';
|
|
21
23
|
import { Dialog, DialogSizes } from './Dialog';
|
|
22
24
|
import { loremIpsum } from '../../stories/knobs/lorem';
|
|
23
25
|
import { chromaticForceScreenSize } from '../../stories/chromaticForceScreenSize';
|
|
@@ -43,8 +45,8 @@ const footer = <footer className="lumx-spacing-padding">Dialog footer</footer>;
|
|
|
43
45
|
function useOpenButton(theme: Theme, defaultState = true) {
|
|
44
46
|
const buttonRef = useRef() as RefObject<HTMLButtonElement>;
|
|
45
47
|
const [isOpen, setOpen] = useState(defaultState);
|
|
46
|
-
const openDialog = () => setOpen(true);
|
|
47
|
-
const closeDialog = () => setOpen(false);
|
|
48
|
+
const openDialog = useCallback(() => setOpen(true), []);
|
|
49
|
+
const closeDialog = useCallback(() => setOpen(false), []);
|
|
48
50
|
|
|
49
51
|
return {
|
|
50
52
|
button: (
|
|
@@ -301,6 +303,9 @@ export const DialogFocusTrap = ({ theme }: any) => {
|
|
|
301
303
|
};
|
|
302
304
|
const [date, setDate] = useState<Date | undefined>(new Date('2020-05-18'));
|
|
303
305
|
|
|
306
|
+
const datePickerDialogButtonRef = useRef<HTMLButtonElement>(null);
|
|
307
|
+
const [isDatePickerDialogOpen, closeDatePickerDialog, openDatePickerDialog] = useBooleanState(false);
|
|
308
|
+
|
|
304
309
|
return (
|
|
305
310
|
<>
|
|
306
311
|
{button}
|
|
@@ -335,16 +340,51 @@ export const DialogFocusTrap = ({ theme }: any) => {
|
|
|
335
340
|
/>
|
|
336
341
|
|
|
337
342
|
<FlexBox orientation="horizontal" hAlign="bottom" gap="regular">
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
343
|
+
<Button ref={datePickerDialogButtonRef} onClick={openDatePickerDialog}>
|
|
344
|
+
Open date picker
|
|
345
|
+
</Button>
|
|
346
|
+
<Dialog
|
|
347
|
+
isOpen={isDatePickerDialogOpen}
|
|
348
|
+
parentElement={datePickerDialogButtonRef}
|
|
349
|
+
onClose={closeDatePickerDialog}
|
|
350
|
+
>
|
|
351
|
+
<header>
|
|
352
|
+
<Toolbar
|
|
353
|
+
label={<h1 className="lumx-typography-title">Date picker</h1>}
|
|
354
|
+
after={
|
|
355
|
+
<IconButton
|
|
356
|
+
label="Close"
|
|
357
|
+
icon={mdiClose}
|
|
358
|
+
onClick={closeDatePickerDialog}
|
|
359
|
+
emphasis={Emphasis.low}
|
|
360
|
+
/>
|
|
361
|
+
}
|
|
362
|
+
/>
|
|
363
|
+
</header>
|
|
364
|
+
<div className="lumx-spacing-padding">
|
|
365
|
+
<DatePickerField
|
|
366
|
+
locale="fr"
|
|
367
|
+
label="Start date"
|
|
368
|
+
placeholder="Pick a date"
|
|
369
|
+
theme={theme}
|
|
370
|
+
onChange={setDate}
|
|
371
|
+
value={date}
|
|
372
|
+
nextButtonProps={{ label: 'Next month' }}
|
|
373
|
+
previousButtonProps={{ label: 'Previous month' }}
|
|
374
|
+
/>
|
|
375
|
+
<DatePickerField
|
|
376
|
+
locale="fr"
|
|
377
|
+
label="Start date"
|
|
378
|
+
placeholder="Pick a date"
|
|
379
|
+
theme={theme}
|
|
380
|
+
onChange={noop}
|
|
381
|
+
value={undefined}
|
|
382
|
+
nextButtonProps={{ label: 'Next month' }}
|
|
383
|
+
previousButtonProps={{ label: 'Previous month' }}
|
|
384
|
+
defaultMonth={new Date('2020-05-18')}
|
|
385
|
+
/>
|
|
386
|
+
</div>
|
|
387
|
+
</Dialog>
|
|
348
388
|
|
|
349
389
|
<Select
|
|
350
390
|
className="lumx-spacing-margin-left-huge"
|
|
@@ -142,7 +142,7 @@ export const Dialog: Comp<DialogProps, HTMLDivElement> = forwardRef((props, ref)
|
|
|
142
142
|
const localContentRef = useRef<HTMLDivElement>(null);
|
|
143
143
|
// Handle focus trap.
|
|
144
144
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
145
|
-
useFocusTrap(wrapperRef.current, focusElement?.current);
|
|
145
|
+
useFocusTrap(isOpen && wrapperRef.current, focusElement?.current);
|
|
146
146
|
|
|
147
147
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
148
148
|
useDisableBodyScroll(isOpen && localContentRef.current);
|
|
@@ -80,23 +80,84 @@ exports[`<Dialog> Snapshots and structure should render story DialogFocusTrap 1`
|
|
|
80
80
|
hAlign="bottom"
|
|
81
81
|
orientation="horizontal"
|
|
82
82
|
>
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
<Button
|
|
84
|
+
emphasis="high"
|
|
85
|
+
onClick={[Function]}
|
|
86
|
+
size="m"
|
|
87
|
+
theme="light"
|
|
88
|
+
>
|
|
89
|
+
Open date picker
|
|
90
|
+
</Button>
|
|
91
|
+
<Dialog
|
|
92
|
+
isOpen={false}
|
|
93
|
+
onClose={[Function]}
|
|
94
|
+
parentElement={
|
|
94
95
|
Object {
|
|
95
|
-
"
|
|
96
|
+
"current": null,
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
size="big"
|
|
100
|
+
>
|
|
101
|
+
<header>
|
|
102
|
+
<Toolbar
|
|
103
|
+
after={
|
|
104
|
+
<IconButton
|
|
105
|
+
emphasis="low"
|
|
106
|
+
icon="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
|
|
107
|
+
label="Close"
|
|
108
|
+
onClick={[Function]}
|
|
109
|
+
size="m"
|
|
110
|
+
theme="light"
|
|
111
|
+
/>
|
|
112
|
+
}
|
|
113
|
+
label={
|
|
114
|
+
<h1
|
|
115
|
+
className="lumx-typography-title"
|
|
116
|
+
>
|
|
117
|
+
Date picker
|
|
118
|
+
</h1>
|
|
119
|
+
}
|
|
120
|
+
/>
|
|
121
|
+
</header>
|
|
122
|
+
<div
|
|
123
|
+
className="lumx-spacing-padding"
|
|
124
|
+
>
|
|
125
|
+
<DatePickerField
|
|
126
|
+
label="Start date"
|
|
127
|
+
locale="fr"
|
|
128
|
+
nextButtonProps={
|
|
129
|
+
Object {
|
|
130
|
+
"label": "Next month",
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
onChange={[Function]}
|
|
134
|
+
placeholder="Pick a date"
|
|
135
|
+
previousButtonProps={
|
|
136
|
+
Object {
|
|
137
|
+
"label": "Previous month",
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
value={2020-05-18T00:00:00.000Z}
|
|
141
|
+
/>
|
|
142
|
+
<DatePickerField
|
|
143
|
+
defaultMonth={2020-05-18T00:00:00.000Z}
|
|
144
|
+
label="Start date"
|
|
145
|
+
locale="fr"
|
|
146
|
+
nextButtonProps={
|
|
147
|
+
Object {
|
|
148
|
+
"label": "Next month",
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
onChange={[Function]}
|
|
152
|
+
placeholder="Pick a date"
|
|
153
|
+
previousButtonProps={
|
|
154
|
+
Object {
|
|
155
|
+
"label": "Previous month",
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
</Dialog>
|
|
100
161
|
<Select
|
|
101
162
|
className="lumx-spacing-margin-left-huge"
|
|
102
163
|
isOpen={false}
|