@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,27 @@
1
+ /** CSS selector listing all tabbable elements. */
2
+ const TABBABLE_ELEMENTS_SELECTOR = `a[href], button, textarea, input:not([type="hidden"]), [tabindex]`;
3
+
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"])`;
6
+
7
+ const isNotDisabled = (element: HTMLElement) => !element.matches(DISABLED_SELECTOR);
8
+
9
+ /**
10
+ * Get first and last elements focusable in an element.
11
+ *
12
+ * @param parentElement The element in which to search focusable elements.
13
+ * @return first and last focusable elements
14
+ */
15
+ export function getFirstAndLastFocusable(parentElement: HTMLElement) {
16
+ const focusableElements = Array.from(parentElement.querySelectorAll<HTMLElement>(TABBABLE_ELEMENTS_SELECTOR));
17
+
18
+ // First non disabled element.
19
+ const first = focusableElements.find(isNotDisabled);
20
+ // Last non disabled element.
21
+ const last = focusableElements.reverse().find(isNotDisabled);
22
+
23
+ if (last && first) {
24
+ return { first, last };
25
+ }
26
+ return {};
27
+ }
@@ -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
@@ -18,6 +18,8 @@ export declare type Comp<P, T = HTMLElement> = {
18
18
  /** Component base class name. */
19
19
  className?: string;
20
20
  };
21
+ /** Union type of all heading elements */
22
+ export declare type HeadingElement = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
21
23
  /**
22
24
  * Define a generic props types.
23
25
  */
@@ -476,9 +478,7 @@ export declare type HTMLButtonProps = DetailedHTMLProps<ButtonHTMLAttributes<HTM
476
478
  * Button size definition.
477
479
  */
478
480
  export declare type ButtonSize = Extract<Size, "s" | "m">;
479
- export interface BaseButtonProps extends GenericProps {
480
- /** ARIA button label. */
481
- ["aria-label"]?: string;
481
+ export interface BaseButtonProps extends GenericProps, Pick<AriaAttributes, "aria-expanded" | "aria-haspopup" | "aria-pressed" | "aria-label"> {
482
482
  /** Color variant. */
483
483
  color?: Color;
484
484
  /** Emphasis variant. */
@@ -743,7 +743,7 @@ export interface DatePickerProps extends GenericProps {
743
743
  /** Props to pass to the previous month button (minus those already set by the DatePickerControlled props). */
744
744
  previousButtonProps: Pick<IconButtonProps, "label"> & Omit<IconButtonProps, "label" | "onClick" | "icon" | "emphasis">;
745
745
  /** Reference to the <button> element corresponding to the current date or the selected date. */
746
- todayOrSelectedDateRef?: RefObject<HTMLButtonElement>;
746
+ todayOrSelectedDateRef?: Ref<HTMLButtonElement>;
747
747
  /** Currently selected date. */
748
748
  value: Date | undefined;
749
749
  /** On change callback. */
@@ -951,6 +951,8 @@ export interface PopoverProps extends GenericProps {
951
951
  isOpen: boolean;
952
952
  /** Offset placement relative to anchor. */
953
953
  offset?: Offset;
954
+ /** Reference to the parent element that triggered the popover (will get back focus on close or else fallback on the anchor element). */
955
+ parentElement?: RefObject<HTMLElement>;
954
956
  /** Placement relative to anchor. */
955
957
  placement?: Placement;
956
958
  /** Whether the popover should be rendered into a DOM node that exists outside the DOM hierarchy of the parent component. */
@@ -1124,6 +1126,41 @@ export interface FlexBoxProps extends GenericProps {
1124
1126
  * @return React element.
1125
1127
  */
1126
1128
  export declare const FlexBox: Comp<FlexBoxProps, HTMLDivElement>;
1129
+ export interface GenericBlockProps extends FlexBoxProps {
1130
+ /** Component to use as visual element. */
1131
+ figure?: ReactNode;
1132
+ /** Actions to set after the main content. */
1133
+ actions?: ReactNode;
1134
+ /** Main content to display */
1135
+ children: ReactNode;
1136
+ /** Orientation of the 3 sections */
1137
+ orientation?: FlexBoxProps["orientation"];
1138
+ /** Horizontal alignment. */
1139
+ hAlign?: FlexBoxProps["hAlign"];
1140
+ /** Vertical alignment. */
1141
+ vAlign?: FlexBoxProps["vAlign"];
1142
+ /**
1143
+ * The props to forward to the content.
1144
+ * By default, the content will have the same alignment as wrapper.
1145
+ */
1146
+ contentProps?: Omit<FlexBoxProps, "children">;
1147
+ /** props to forward to the actions element. */
1148
+ actionsProps?: Omit<FlexBoxProps, "children">;
1149
+ /** props to forward to the figure element. */
1150
+ figureProps?: Omit<FlexBoxProps, "children">;
1151
+ }
1152
+ /**
1153
+ * The GenericBlock is a layout component made of 3 sections that can be
1154
+ * displayed either horizontally of vertically with the same gap between each section.
1155
+ *
1156
+ * The sections are:
1157
+ * * (Optional) `Figure` => A visual element to display before the main content.
1158
+ * * (Required) `Content` => The main content displayed
1159
+ * * (Optional) `Actions` => One or more actions to set after the element.
1160
+ *
1161
+ * @see https://www.figma.com/file/lzzrQmsfaXRaOyRfoEogPZ/DS%3A-playground?node-id=1%3A4076
1162
+ */
1163
+ export declare const GenericBlock: Comp<GenericBlockProps, HTMLDivElement>;
1127
1164
  export declare type GridGutterSize = Extract<Size, "regular" | "big" | "huge">;
1128
1165
  /**
1129
1166
  * Defines the props of the component.
@@ -1433,12 +1470,12 @@ export declare const Link: Comp<LinkProps, HTMLAnchorElement | HTMLButtonElement
1433
1470
  * Defines the props of the component.
1434
1471
  */
1435
1472
  export interface LinkPreviewProps extends GenericProps {
1436
- /** Description (either a string, or sanitized html). */
1437
- description?: string | {
1438
- __html: string;
1439
- };
1473
+ /** Description. */
1474
+ description?: string;
1440
1475
  /** Link URL. */
1441
1476
  link: string;
1477
+ /** Custom react component for the link (can be used to inject react router Link). */
1478
+ linkAs?: "a" | any;
1442
1479
  /** Props to pass to the link (minus those already set by the LinkPreview props). */
1443
1480
  linkProps?: Omit<LinkProps, "color" | "colorVariant" | "href" | "target">;
1444
1481
  /** Size variant. */
@@ -1449,6 +1486,8 @@ export interface LinkPreviewProps extends GenericProps {
1449
1486
  thumbnailProps?: ThumbnailProps;
1450
1487
  /** Title. */
1451
1488
  title?: string;
1489
+ /** Customize the title heading tag. */
1490
+ titleHeading?: HeadingElement;
1452
1491
  }
1453
1492
  /**
1454
1493
  * LinkPreview component.
@@ -1858,6 +1897,8 @@ export interface CoreSelectProps extends GenericProps {
1858
1897
  helper?: string;
1859
1898
  /** Whether the select should close on click. */
1860
1899
  closeOnClick?: boolean;
1900
+ /** Icon (SVG path). */
1901
+ icon?: string;
1861
1902
  /** Whether the component is disabled or not. */
1862
1903
  isDisabled?: boolean;
1863
1904
  /** Whether the component is required or not. */
@@ -2646,7 +2687,7 @@ export declare type UserBlockSize = Extract<Size, "s" | "m" | "l">;
2646
2687
  */
2647
2688
  export interface UserBlockProps extends GenericProps {
2648
2689
  /** Props to pass to the avatar. */
2649
- avatarProps?: AvatarProps;
2690
+ avatarProps?: Omit<AvatarProps, "alt">;
2650
2691
  /** Additional fields used to describe the user. */
2651
2692
  fields?: string[];
2652
2693
  /** Props to pass to the link wrapping the avatar thumbnail. */
@@ -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
- `;