@lumx/react 2.2.12-alpha.1 → 2.2.13

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 (35) hide show
  1. package/esm/_internal/CommentBlock.js +12 -5
  2. package/esm/_internal/CommentBlock.js.map +1 -1
  3. package/esm/_internal/Dropdown2.js +5 -2
  4. package/esm/_internal/Dropdown2.js.map +1 -1
  5. package/esm/_internal/Icon2.js +20 -40
  6. package/esm/_internal/Icon2.js.map +1 -1
  7. package/esm/_internal/List2.js +11 -2
  8. package/esm/_internal/List2.js.map +1 -1
  9. package/esm/_internal/Popover2.js +69 -4
  10. package/esm/_internal/Popover2.js.map +1 -1
  11. package/esm/_internal/Slides.js +1 -24
  12. package/esm/_internal/Slides.js.map +1 -1
  13. package/esm/_internal/Tooltip2.js +1 -3
  14. package/esm/_internal/Tooltip2.js.map +1 -1
  15. package/esm/_internal/comment-block.js +8 -0
  16. package/esm/_internal/comment-block.js.map +1 -1
  17. package/package.json +4 -4
  18. package/src/components/autocomplete/__snapshots__/Autocomplete.test.tsx.snap +4 -0
  19. package/src/components/autocomplete/__snapshots__/AutocompleteMultiple.test.tsx.snap +1 -0
  20. package/src/components/comment-block/CommentBlock.stories.tsx +7 -4
  21. package/src/components/comment-block/CommentBlock.tsx +13 -3
  22. package/src/components/comment-block/__snapshots__/CommentBlock.test.tsx.snap +10 -5
  23. package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +1 -0
  24. package/src/components/dropdown/Dropdown.tsx +5 -0
  25. package/src/components/dropdown/__snapshots__/Dropdown.test.tsx.snap +1 -0
  26. package/src/components/icon/Icon.stories.tsx +12 -0
  27. package/src/components/icon/Icon.tsx +16 -37
  28. package/src/components/icon/__snapshots__/Icon.test.tsx.snap +1 -1
  29. package/src/components/list/List.tsx +12 -2
  30. package/src/components/list/__snapshots__/List.test.tsx.snap +5 -5
  31. package/src/components/popover/Popover.tsx +42 -2
  32. package/src/components/select/__snapshots__/Select.test.tsx.snap +1 -0
  33. package/src/components/select/__snapshots__/SelectMultiple.test.tsx.snap +2 -0
  34. package/src/components/tooltip/useTooltipOpen.tsx +0 -1
  35. package/types.d.ts +9 -1
@@ -58,6 +58,8 @@ export interface DropdownProps extends GenericProps {
58
58
  placement?: Placement;
59
59
  /** Whether the focus should be set on the list when the dropdown is open or not. */
60
60
  shouldFocusOnOpen?: boolean;
61
+ /** Whether the focus should go back on the anchor when dropdown closes and focus is within. */
62
+ focusAnchorOnClose?: boolean;
61
63
  /**
62
64
  * Z-axis position.
63
65
  * @see {@link PopoverProps#zIndex}
@@ -93,6 +95,7 @@ const DEFAULT_PROPS: Partial<DropdownProps> = {
93
95
  fitWithinViewportHeight: true,
94
96
  placement: Placement.BOTTOM_START,
95
97
  shouldFocusOnOpen: true,
98
+ focusAnchorOnClose: true,
96
99
  };
97
100
 
98
101
  /**
@@ -114,6 +117,7 @@ export const Dropdown: Comp<DropdownProps, HTMLDivElement> = forwardRef((props,
114
117
  fitWithinViewportHeight,
115
118
  isOpen,
116
119
  offset,
120
+ focusAnchorOnClose,
117
121
  onClose,
118
122
  onInfiniteScroll,
119
123
  placement,
@@ -147,6 +151,7 @@ export const Dropdown: Comp<DropdownProps, HTMLDivElement> = forwardRef((props,
147
151
  <Popover
148
152
  ref={ref}
149
153
  {...forwardedProps}
154
+ focusAnchorOnClose={focusAnchorOnClose}
150
155
  anchorRef={anchorRef}
151
156
  className={classNames(className, handleBasicClasses({ prefix: CLASSNAME }))}
152
157
  elevation={0 as any}
@@ -13,6 +13,7 @@ exports[`<Dropdown> Snapshots and structure should render correctly 1`] = `
13
13
  elevation={0}
14
14
  fitToAnchorWidth={true}
15
15
  fitWithinViewportHeight={true}
16
+ focusAnchorOnClose={true}
16
17
  focusElement={
17
18
  Object {
18
19
  "current": null,
@@ -42,6 +42,18 @@ const TemplateColorVariants = ({ hasShape, theme }: any) => {
42
42
  <br />
43
43
  {withUndefined(Object.values(ColorVariant).reverse()).map((colorVariant) => (
44
44
  <Fragment key={`${colorVariant}`}>
45
+ {!colorVariant && (
46
+ <>
47
+ <small>No theme</small>
48
+ <Icon
49
+ icon={mdiEmail}
50
+ color={color}
51
+ colorVariant={colorVariant}
52
+ size="m"
53
+ hasShape={hasShape}
54
+ />
55
+ </>
56
+ )}
45
57
  <small>Variant: {colorVariant || 'undefined'}</small>
46
58
  <Icon
47
59
  icon={mdiEmail}
@@ -56,46 +56,25 @@ const DEFAULT_PROPS: Partial<IconProps> = {};
56
56
  export const Icon: Comp<IconProps, HTMLElement> = forwardRef((props, ref) => {
57
57
  const { className, color, colorVariant, hasShape, icon, size, theme, alt, ...forwardedProps } = props;
58
58
 
59
- let iconColor;
60
- let iconColorVariant;
61
- let iconTheme;
62
- if (color) {
63
- iconColor = color;
64
- iconTheme = theme;
59
+ // Color
60
+ let iconColor = color;
61
+ if (!iconColor && (hasShape || theme)) {
62
+ iconColor = theme === Theme.dark ? ColorPalette.light : ColorPalette.dark;
65
63
  }
66
64
 
67
- if (hasShape) {
68
- if (theme === Theme.dark && !iconColor) {
69
- iconColor = ColorPalette.light;
70
- iconTheme = theme;
71
- } else {
72
- iconColor = iconColor || ColorPalette.dark;
73
- }
74
- } else if (!iconColor && theme) {
75
- iconTheme = theme;
76
- iconColor = iconColor || theme === Theme.light ? ColorPalette.dark : ColorPalette.light;
77
- }
78
-
79
- if (!iconColorVariant) {
80
- if (hasShape && iconColor === ColorPalette.dark) {
81
- iconColorVariant = colorVariant || 'L2';
82
- } else {
83
- iconColorVariant = colorVariant || (theme === Theme.dark ? 'N' : 'L1');
84
- }
65
+ // Color variant
66
+ let iconColorVariant = colorVariant;
67
+ if (!iconColorVariant && hasShape && iconColor === ColorPalette.dark) {
68
+ iconColorVariant = 'L2';
85
69
  }
86
70
 
87
- let iconSize;
88
- if (size) {
89
- if (hasShape) {
90
- if (size === Size.xxs || size === Size.xs) {
91
- iconSize = Size.s;
92
- } else if (size === Size.xxl) {
93
- iconSize = Size.xl;
94
- } else {
95
- iconSize = size;
96
- }
97
- } else {
98
- iconSize = size;
71
+ // Size
72
+ let iconSize = size;
73
+ if (size && hasShape) {
74
+ if (size === Size.xxs || size === Size.xs) {
75
+ iconSize = Size.s;
76
+ } else if (size === Size.xxl) {
77
+ iconSize = Size.xl;
99
78
  }
100
79
  } else if (hasShape) {
101
80
  iconSize = Size.m;
@@ -112,7 +91,7 @@ export const Icon: Comp<IconProps, HTMLElement> = forwardRef((props, ref) => {
112
91
  colorVariant: iconColorVariant,
113
92
  hasShape,
114
93
  prefix: CLASSNAME,
115
- theme: iconTheme,
94
+ theme,
116
95
  size: iconSize,
117
96
  }),
118
97
  !hasShape && `${CLASSNAME}--no-shape`,
@@ -26,7 +26,7 @@ exports[`<Icon> Snapshots and structure should render color & color variant 1`]
26
26
 
27
27
  exports[`<Icon> Snapshots and structure should render correctly 1`] = `
28
28
  <i
29
- className="lumx-icon lumx-icon--color-variant-L1 lumx-icon--no-shape lumx-icon--path"
29
+ className="lumx-icon lumx-icon--no-shape lumx-icon--path"
30
30
  >
31
31
  <svg
32
32
  aria-hidden="true"
@@ -21,6 +21,8 @@ export interface ListProps extends GenericProps {
21
21
  isClickable?: boolean;
22
22
  /** Item padding size. */
23
23
  itemPadding?: Extract<Size, 'big' | 'huge'>;
24
+ /** Tab index of the list. Default to -1 */
25
+ tabIndex?: number;
24
26
  /**
25
27
  * On list item selected callback.
26
28
  *
@@ -41,6 +43,13 @@ const COMPONENT_NAME = 'List';
41
43
  */
42
44
  const CLASSNAME = getRootClassName(COMPONENT_NAME);
43
45
 
46
+ /**
47
+ * Component default props.
48
+ */
49
+ const DEFAULT_PROPS: Partial<ListProps> = {
50
+ tabIndex: -1,
51
+ };
52
+
44
53
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
45
54
  /**
46
55
  * List component.
@@ -50,7 +59,7 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
50
59
  * @return React element.
51
60
  */
52
61
  const InternalList: Comp<ListProps, HTMLUListElement> = forwardRef((props, ref) => {
53
- const { children, className, isClickable, itemPadding, onListItemSelected, ...forwardedProps } = props;
62
+ const { children, className, isClickable, itemPadding, onListItemSelected, tabIndex, ...forwardedProps } = props;
54
63
  const listElementRef = useRef<HTMLUListElement>(null);
55
64
 
56
65
  const { items, hasClickableItem } = useInteractiveList({
@@ -70,7 +79,7 @@ const InternalList: Comp<ListProps, HTMLUListElement> = forwardRef((props, ref)
70
79
  itemPadding: itemPadding ?? (clickable ? Size.big : undefined),
71
80
  }),
72
81
  )}
73
- tabIndex={clickable ? 0 : -1}
82
+ tabIndex={tabIndex}
74
83
  ref={mergeRefs(ref, listElementRef)}
75
84
  >
76
85
  {items}
@@ -79,5 +88,6 @@ const InternalList: Comp<ListProps, HTMLUListElement> = forwardRef((props, ref)
79
88
  });
80
89
  InternalList.displayName = COMPONENT_NAME;
81
90
  InternalList.className = CLASSNAME;
91
+ InternalList.defaultProps = DEFAULT_PROPS;
82
92
 
83
93
  export const List = Object.assign(InternalList, { useKeyboardListNavigation });
@@ -3,7 +3,7 @@
3
3
  exports[`<List> Snapshots and structure should render story 'AsLink' 1`] = `
4
4
  <ul
5
5
  className="lumx-list lumx-list--item-padding-big"
6
- tabIndex={0}
6
+ tabIndex={-1}
7
7
  >
8
8
  <ListItem
9
9
  before={
@@ -62,7 +62,7 @@ exports[`<List> Snapshots and structure should render story 'AsLink' 1`] = `
62
62
  exports[`<List> Snapshots and structure should render story 'KeyboardNavigation' 1`] = `
63
63
  <ul
64
64
  className="lumx-list lumx-list--item-padding-big"
65
- tabIndex={0}
65
+ tabIndex={-1}
66
66
  >
67
67
  <ListItem
68
68
  isHighlighted={false}
@@ -193,7 +193,7 @@ exports[`<List> Snapshots and structure should render story 'WithItemPadding' 1`
193
193
  Array [
194
194
  <ul
195
195
  className="lumx-list lumx-list--item-padding-big"
196
- tabIndex={0}
196
+ tabIndex={-1}
197
197
  >
198
198
  <ListItem
199
199
  className="lumx-color-background-dark-L6"
@@ -248,7 +248,7 @@ Array [
248
248
  </ul>,
249
249
  <ul
250
250
  className="lumx-list lumx-list--item-padding-big"
251
- tabIndex={0}
251
+ tabIndex={-1}
252
252
  >
253
253
  <ListItem
254
254
  className="lumx-color-background-dark-L6"
@@ -303,7 +303,7 @@ Array [
303
303
  </ul>,
304
304
  <ul
305
305
  className="lumx-list lumx-list--item-padding-huge"
306
- tabIndex={0}
306
+ tabIndex={-1}
307
307
  >
308
308
  <ListItem
309
309
  className="lumx-color-background-dark-L6"
@@ -12,6 +12,7 @@ import { ClickAwayProvider } from '@lumx/react/utils/ClickAwayProvider';
12
12
 
13
13
  import { Comp, GenericProps, getRootClassName, handleBasicClasses, ValueOf } from '@lumx/react/utils';
14
14
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
15
+ import { useFocusWithin } from '@lumx/react/hooks/useFocusWithin';
15
16
 
16
17
  /**
17
18
  * Different possible placements for the popover.
@@ -81,6 +82,8 @@ export interface PopoverProps extends GenericProps {
81
82
  fitWithinViewportHeight?: boolean;
82
83
  /** Element to focus when opening the popover. */
83
84
  focusElement?: RefObject<HTMLElement>;
85
+ /** Whether the focus should go back on the anchor when popover closes and focus is within. */
86
+ focusAnchorOnClose?: boolean;
84
87
  /** Whether we put an arrow or not. */
85
88
  hasArrow?: boolean;
86
89
  /** Whether the popover is open or not. */
@@ -213,6 +216,7 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
213
216
  style,
214
217
  usePortal,
215
218
  zIndex,
219
+ focusAnchorOnClose = true,
216
220
  ...forwardedProps
217
221
  } = props;
218
222
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -222,6 +226,42 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
222
226
  // eslint-disable-next-line react-hooks/rules-of-hooks
223
227
  const clickAwayRef = useRef<HTMLDivElement>(null);
224
228
 
229
+ /**
230
+ * Track whether the focus is currently set in the
231
+ * popover.
232
+ * */
233
+ // eslint-disable-next-line react-hooks/rules-of-hooks
234
+ const isFocusedWithin = useRef(false);
235
+
236
+ // eslint-disable-next-line react-hooks/rules-of-hooks
237
+ useFocusWithin({
238
+ element: popperElement || null,
239
+ onFocusIn: () => {
240
+ isFocusedWithin.current = true;
241
+ },
242
+ onFocusOut: () => {
243
+ isFocusedWithin.current = false;
244
+ },
245
+ });
246
+
247
+ /** Action on close */
248
+ const handleClose = () => {
249
+ if (!onClose) {
250
+ return;
251
+ }
252
+
253
+ /**
254
+ * If the focus is currently within the popover
255
+ * when the popover closes, reset the focus back to the anchor element
256
+ * unless specifically requested not to.
257
+ */
258
+ if (isFocusedWithin.current && focusAnchorOnClose) {
259
+ anchorRef.current?.focus();
260
+ }
261
+
262
+ onClose();
263
+ };
264
+
225
265
  const modifiers: any = [];
226
266
  const actualOffset: [number, number] = [offset?.along ?? 0, (offset?.away ?? 0) + (hasArrow ? ARROW_SIZE : 0)];
227
267
  modifiers.push({
@@ -267,7 +307,7 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
267
307
  }, [style, styles.popper, zIndex, fitWithinViewportHeight]);
268
308
 
269
309
  // eslint-disable-next-line react-hooks/rules-of-hooks
270
- useCallbackOnEscape(onClose, isOpen && closeOnEscape);
310
+ useCallbackOnEscape(handleClose, isOpen && closeOnEscape);
271
311
  // eslint-disable-next-line react-hooks/rules-of-hooks
272
312
  useFocus(focusElement?.current, isOpen && (state?.rects?.popper?.y ?? -1) >= 0);
273
313
 
@@ -286,7 +326,7 @@ export const Popover: Comp<PopoverProps, HTMLDivElement> = forwardRef((props, re
286
326
  style={popoverStyle}
287
327
  {...attributes.popper}
288
328
  >
289
- <ClickAwayProvider callback={closeOnClickAway && onClose} refs={clickAwayRefs}>
329
+ <ClickAwayProvider callback={closeOnClickAway && handleClose} refs={clickAwayRefs}>
290
330
  {hasArrow && <div ref={setArrowElement} className={`${CLASSNAME}__arrow`} style={styles.arrow} />}
291
331
  {children}
292
332
  </ClickAwayProvider>
@@ -29,6 +29,7 @@ exports[`<Select> Snapshots and structure should render correctly 1`] = `
29
29
  closeOnEscape={true}
30
30
  fitToAnchorWidth={true}
31
31
  fitWithinViewportHeight={true}
32
+ focusAnchorOnClose={true}
32
33
  isOpen={false}
33
34
  onClose={[Function]}
34
35
  placement="bottom-start"
@@ -30,6 +30,7 @@ exports[`<SelectMultiple> Snapshots and structure should render chips 1`] = `
30
30
  closeOnEscape={true}
31
31
  fitToAnchorWidth={true}
32
32
  fitWithinViewportHeight={true}
33
+ focusAnchorOnClose={true}
33
34
  isOpen={false}
34
35
  onClose={[Function]}
35
36
  placement="bottom-start"
@@ -72,6 +73,7 @@ exports[`<SelectMultiple> Snapshots and structure should render defaults 1`] = `
72
73
  closeOnEscape={true}
73
74
  fitToAnchorWidth={true}
74
75
  fitWithinViewportHeight={true}
76
+ focusAnchorOnClose={true}
75
77
  isOpen={false}
76
78
  onClose={[Function]}
77
79
  placement="bottom-start"
@@ -103,7 +103,6 @@ export function useTooltipOpen(delay: number | undefined, anchorElement: HTMLEle
103
103
  for (const [node, eventType, evenHandler] of events) {
104
104
  node.removeEventListener(eventType, evenHandler);
105
105
  }
106
- closeImmediately();
107
106
  };
108
107
  }, [anchorElement, delay]);
109
108
 
package/types.d.ts CHANGED
@@ -688,8 +688,10 @@ export interface CommentBlockProps extends GenericProps {
688
688
  avatarProps: AvatarProps;
689
689
  /** Comment block replies. */
690
690
  children?: ReactNode;
691
- /** Comment date. */
691
+ /** Comment date with the minimal timestamp informations (xx minutes, x hours, yesterday, 6 days, Month Day, Month Day Year)*/
692
692
  date: string;
693
+ /** Comment date with the full timestamp informations (day, month, year, time) */
694
+ fullDate?: string;
693
695
  /** Whether the component has actions to display or not. */
694
696
  hasActions?: boolean;
695
697
  /** Action toolbar header content. */
@@ -938,6 +940,8 @@ export interface PopoverProps extends GenericProps {
938
940
  fitWithinViewportHeight?: boolean;
939
941
  /** Element to focus when opening the popover. */
940
942
  focusElement?: RefObject<HTMLElement>;
943
+ /** Whether the focus should go back on the anchor when popover closes and focus is within. */
944
+ focusAnchorOnClose?: boolean;
941
945
  /** Whether we put an arrow or not. */
942
946
  hasArrow?: boolean;
943
947
  /** Whether the popover is open or not. */
@@ -1012,6 +1016,8 @@ export interface DropdownProps extends GenericProps {
1012
1016
  placement?: Placement;
1013
1017
  /** Whether the focus should be set on the list when the dropdown is open or not. */
1014
1018
  shouldFocusOnOpen?: boolean;
1019
+ /** Whether the focus should go back on the anchor when dropdown closes and focus is within. */
1020
+ focusAnchorOnClose?: boolean;
1015
1021
  /**
1016
1022
  * Z-axis position.
1017
1023
  * @see {@link PopoverProps#zIndex}
@@ -1474,6 +1480,8 @@ export interface ListProps extends GenericProps {
1474
1480
  isClickable?: boolean;
1475
1481
  /** Item padding size. */
1476
1482
  itemPadding?: Extract<Size, "big" | "huge">;
1483
+ /** Tab index of the list. Default to -1 */
1484
+ tabIndex?: number;
1477
1485
  /**
1478
1486
  * On list item selected callback.
1479
1487
  *