@lumx/react 2.1.1 → 2.1.5

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 (78) hide show
  1. package/README.md +1 -1
  2. package/esm/_internal/Avatar2.js +5 -1
  3. package/esm/_internal/Avatar2.js.map +1 -1
  4. package/esm/_internal/Button2.js.map +1 -1
  5. package/esm/_internal/ButtonRoot.js +14 -4
  6. package/esm/_internal/ButtonRoot.js.map +1 -1
  7. package/esm/_internal/ClickAwayProvider.js +1 -1
  8. package/esm/_internal/Dialog2.js +13 -8
  9. package/esm/_internal/Dialog2.js.map +1 -1
  10. package/esm/_internal/DragHandle.js +1 -1
  11. package/esm/_internal/DragHandle.js.map +1 -1
  12. package/esm/_internal/Flag2.js +1 -3
  13. package/esm/_internal/Flag2.js.map +1 -1
  14. package/esm/_internal/IconButton.js +0 -2
  15. package/esm/_internal/IconButton.js.map +1 -1
  16. package/esm/_internal/List2.js +16 -9
  17. package/esm/_internal/List2.js.map +1 -1
  18. package/esm/_internal/Message2.js +2 -2
  19. package/esm/_internal/Message2.js.map +1 -1
  20. package/esm/_internal/SlideshowControls.js +3 -3
  21. package/esm/_internal/SlideshowControls.js.map +1 -1
  22. package/esm/_internal/TextField.js +5 -2
  23. package/esm/_internal/TextField.js.map +1 -1
  24. package/esm/_internal/Thumbnail2.js +29 -34
  25. package/esm/_internal/Thumbnail2.js.map +1 -1
  26. package/esm/_internal/Tooltip2.js +1 -1
  27. package/esm/_internal/UserBlock.js +44 -14
  28. package/esm/_internal/UserBlock.js.map +1 -1
  29. package/esm/_internal/getRootClassName.js +17 -1
  30. package/esm/_internal/getRootClassName.js.map +1 -1
  31. package/esm/_internal/user-block.js +1 -0
  32. package/esm/_internal/user-block.js.map +1 -1
  33. package/package.json +4 -8
  34. package/src/components/avatar/Avatar.stories.tsx +1 -1
  35. package/src/components/avatar/Avatar.tsx +8 -0
  36. package/src/components/button/Button.stories.tsx +85 -15
  37. package/src/components/button/Button.tsx +2 -0
  38. package/src/components/button/ButtonRoot.test.tsx +13 -0
  39. package/src/components/button/ButtonRoot.tsx +10 -1
  40. package/src/components/button/IconButton.test.tsx +9 -0
  41. package/src/components/button/IconButton.tsx +11 -26
  42. package/src/components/button/__snapshots__/ButtonRoot.test.tsx.snap +13 -0
  43. package/src/components/button/__snapshots__/IconButton.test.tsx.snap +19 -0
  44. package/src/components/comment-block/CommentBlock.stories.tsx +1 -1
  45. package/src/components/dialog/Dialog.stories.tsx +45 -3
  46. package/src/components/dialog/Dialog.tsx +15 -11
  47. package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +76 -0
  48. package/src/components/drag-handle/DragHandle.tsx +5 -1
  49. package/src/components/flag/Flag.test.tsx +1 -2
  50. package/src/components/flag/Flag.tsx +2 -10
  51. package/src/components/flag/__snapshots__/Flag.test.tsx.snap +0 -15
  52. package/src/components/image-block/ImageBlock.stories.tsx +1 -1
  53. package/src/components/link-preview/LinkPreview.stories.tsx +1 -1
  54. package/src/components/list/List.stories.tsx +7 -1
  55. package/src/components/list/ListItem.stories.tsx +28 -3
  56. package/src/components/list/ListItem.tsx +25 -7
  57. package/src/components/list/__snapshots__/List.test.tsx.snap +23 -3
  58. package/src/components/list/__snapshots__/ListItem.test.tsx.snap +84 -11
  59. package/src/components/list/useInteractiveList.tsx +1 -1
  60. package/src/components/message/Message.tsx +2 -2
  61. package/src/components/skeleton/SkeletonRectangle.stories.tsx +1 -1
  62. package/src/components/slideshow/useKeyNavigate.ts +2 -2
  63. package/src/components/text-field/TextField.stories.tsx +97 -82
  64. package/src/components/text-field/TextField.tsx +5 -0
  65. package/src/components/thumbnail/Thumbnail.stories.tsx +22 -1
  66. package/src/components/thumbnail/Thumbnail.test.tsx +20 -2
  67. package/src/components/thumbnail/Thumbnail.tsx +40 -15
  68. package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +53 -6
  69. package/src/components/user-block/UserBlock.stories.tsx +28 -5
  70. package/src/components/user-block/UserBlock.tsx +40 -16
  71. package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +244 -145
  72. package/src/stories/generated/Button/Demos.stories.tsx +1 -0
  73. package/src/stories/knobs/buttonKnob.ts +9 -0
  74. package/src/stories/knobs/emphasisKnob.ts +8 -0
  75. package/src/utils/MaterialThemeSwitcher/MaterialThemeSwitcher.tsx +54 -0
  76. package/src/utils/MaterialThemeSwitcher/index.ts +1 -0
  77. package/src/stories/knobs/index.ts +0 -2
  78. package/types.d.ts +0 -2561
@@ -4,27 +4,17 @@ import { Emphasis, Icon, Size, Theme, Tooltip, TooltipProps } from '@lumx/react'
4
4
  import { BaseButtonProps, ButtonRoot } from '@lumx/react/components/button/ButtonRoot';
5
5
  import { Comp, getRootClassName } from '@lumx/react/utils';
6
6
 
7
- /** Either icon or image prop must be defined */
8
- type ImageOrIconType =
9
- /** Svg path type icon */
10
- | {
11
- /**
12
- * Icon SVG path (recommended over an image).
13
- */
14
- icon: string;
15
- image?: undefined;
16
- }
17
- /** Image url type icon */
18
- | {
19
- /**
20
- * Image URL (use icon SVG path when possible).
21
- */
22
- image: string;
23
- icon?: undefined;
24
- };
25
-
26
- /** Props common to icon and image type icon. */
27
- export interface IconButtonBaseProps {
7
+ export interface IconButtonProps extends BaseButtonProps {
8
+ /**
9
+ * Icon (SVG path).
10
+ * If `image` is also set, `image` will be used instead.
11
+ */
12
+ icon?: string;
13
+ /**
14
+ * Image (image url).
15
+ * Has priority over `icon`.
16
+ */
17
+ image?: string;
28
18
  /**
29
19
  * Label text (required for a11y purpose).
30
20
  * If you really don't want an aria-label, you can set an empty label (this is not recommended).
@@ -39,11 +29,6 @@ export interface IconButtonBaseProps {
39
29
  hideTooltip?: boolean;
40
30
  }
41
31
 
42
- /**
43
- * Defines the props of the component.
44
- */
45
- export type IconButtonProps = IconButtonBaseProps & ImageOrIconType & BaseButtonProps;
46
-
47
32
  /**
48
33
  * Component display name.
49
34
  */
@@ -1,5 +1,18 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`<ButtonRoot> Props should be full width 1`] = `
4
+ <ButtonRoot
5
+ emphasis="high"
6
+ fullWidth={true}
7
+ theme="light"
8
+ >
9
+ <button
10
+ className="lumx-button lumx-button--color-primary lumx-button--emphasis-high lumx-button--theme-light lumx-button--is-full-width"
11
+ type="button"
12
+ />
13
+ </ButtonRoot>
14
+ `;
15
+
3
16
  exports[`<ButtonRoot> Props should not have default color in low or medium emphasis 1`] = `
4
17
  <ButtonRoot
5
18
  emphasis="low"
@@ -67,3 +67,22 @@ exports[`<IconButton> Snapshots and structure should render icon button with an
67
67
  </ButtonRoot>
68
68
  </Tooltip>
69
69
  `;
70
+
71
+ exports[`<IconButton> Snapshots and structure should render icon button with an image if both props are set 1`] = `
72
+ <Tooltip
73
+ delay={500}
74
+ placement="bottom"
75
+ >
76
+ <ButtonRoot
77
+ emphasis="high"
78
+ size="m"
79
+ theme="light"
80
+ variant="icon"
81
+ >
82
+ <img
83
+ alt=""
84
+ src="http://foo.com"
85
+ />
86
+ </ButtonRoot>
87
+ </Tooltip>
88
+ `;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { mdiDotsHorizontal, mdiHeart, mdiReply } from '@lumx/icons';
3
3
  import { Button, CommentBlock, Emphasis, Size } from '@lumx/react';
4
4
  import { IconButton } from '@lumx/react/components/button/IconButton';
5
- import { avatarImageKnob } from '@lumx/react/stories/knobs';
5
+ import { avatarImageKnob } from '@lumx/react/stories/knobs/image';
6
6
 
7
7
  export default { title: 'LumX components/comment-block/CommentBlock' };
8
8
 
@@ -1,5 +1,6 @@
1
1
  import { mdiClose } from '@lumx/icons';
2
2
  import {
3
+ AlertDialog,
3
4
  Button,
4
5
  Checkbox,
5
6
  DatePickerField,
@@ -17,7 +18,7 @@ import {
17
18
  import { select } from '@storybook/addon-knobs';
18
19
  import React, { RefObject, useRef, useState } from 'react';
19
20
  import { Dialog, DialogSizes } from './Dialog';
20
- import { loremIpsum } from '../../stories/knobs';
21
+ import { loremIpsum } from '../../stories/knobs/lorem';
21
22
 
22
23
  export default {
23
24
  title: 'LumX components/dialog/Dialog',
@@ -32,9 +33,9 @@ const content = <div className="lumx-spacing-padding">{loremIpsum('short')}</div
32
33
  const longContent = <div className="lumx-spacing-padding">{loremIpsum('long')}</div>;
33
34
  const footer = <footer className="lumx-spacing-padding">Dialog footer</footer>;
34
35
 
35
- function useOpenButton(theme: Theme) {
36
+ function useOpenButton(theme: Theme, defaultState = true) {
36
37
  const buttonRef = useRef() as RefObject<HTMLButtonElement>;
37
- const [isOpen, setOpen] = useState(true);
38
+ const [isOpen, setOpen] = useState(defaultState);
38
39
  const openDialog = () => setOpen(true);
39
40
  const closeDialog = () => setOpen(false);
40
41
 
@@ -45,6 +46,7 @@ function useOpenButton(theme: Theme) {
45
46
  </Button>
46
47
  ),
47
48
  buttonRef,
49
+ openDialog,
48
50
  closeDialog,
49
51
  isOpen,
50
52
  };
@@ -83,6 +85,46 @@ export const PreventDialogAutoClose = ({ theme }: any) => {
83
85
  );
84
86
  };
85
87
 
88
+ export const DialogWithAlertDialog = ({ theme }: any) => {
89
+ const { button, buttonRef, closeDialog, isOpen } = useOpenButton(theme);
90
+ const { openDialog: openAlertDialog, closeDialog: closeAlertDialog, isOpen: isAlertDialogOpen } = useOpenButton(
91
+ theme,
92
+ false,
93
+ );
94
+
95
+ const handleSubmitDialog = () => {
96
+ closeDialog();
97
+ openAlertDialog();
98
+ };
99
+
100
+ return (
101
+ <>
102
+ {button}
103
+ <Dialog isOpen={isOpen} onClose={closeDialog} parentElement={buttonRef}>
104
+ {content}
105
+ <footer>
106
+ <Toolbar
107
+ after={
108
+ <Button onClick={handleSubmitDialog} emphasis={Emphasis.low}>
109
+ Close
110
+ </Button>
111
+ }
112
+ />
113
+ </footer>
114
+ </Dialog>
115
+ <AlertDialog
116
+ isOpen={isAlertDialogOpen}
117
+ onClose={closeDialog}
118
+ parentElement={buttonRef}
119
+ title="Default (info)"
120
+ confirmProps={{ onClick: closeAlertDialog, label: 'Confirm' }}
121
+ >
122
+ Consequat deserunt officia aute laborum tempor anim sint est.
123
+ </AlertDialog>
124
+ </>
125
+ );
126
+ };
127
+
86
128
  export const Sizes = ({ theme }: any) => {
87
129
  const { button, buttonRef, closeDialog, isOpen } = useOpenButton(theme);
88
130
  const sizes: DialogSizes[] = [Size.tiny, Size.regular, Size.big, Size.huge];
@@ -115,18 +115,22 @@ export const Dialog: Comp<DialogProps, HTMLDivElement> = forwardRef((props, ref)
115
115
  ...forwardedProps
116
116
  } = props;
117
117
 
118
- const handleClose = onClose
119
- ? () => {
120
- onClose();
121
- // Focus the parent element on close.
122
- if (parentElement && parentElement.current) {
123
- parentElement.current.focus();
124
- }
125
- }
126
- : undefined;
118
+ // eslint-disable-next-line react-hooks/rules-of-hooks
119
+ const previousOpen = React.useRef(isOpen);
120
+ // eslint-disable-next-line react-hooks/rules-of-hooks
121
+ React.useEffect(() => {
122
+ if (isOpen !== previousOpen.current) {
123
+ previousOpen.current = isOpen;
124
+
125
+ // Focus the parent element on close.
126
+ if (!isOpen && parentElement && parentElement.current) {
127
+ parentElement.current.focus();
128
+ }
129
+ }
130
+ }, [isOpen, parentElement]);
127
131
 
128
132
  // eslint-disable-next-line react-hooks/rules-of-hooks
129
- useCallbackOnEscape(handleClose, isOpen && !preventAutoClose);
133
+ useCallbackOnEscape(onClose, isOpen && !preventAutoClose);
130
134
 
131
135
  // eslint-disable-next-line react-hooks/rules-of-hooks
132
136
  const wrapperRef = useRef<HTMLDivElement>(null);
@@ -192,7 +196,7 @@ export const Dialog: Comp<DialogProps, HTMLDivElement> = forwardRef((props, ref)
192
196
  <div className={`${CLASSNAME}__overlay`} />
193
197
 
194
198
  <section className={`${CLASSNAME}__container`} role="dialog" aria-modal="true" {...dialogProps}>
195
- <ClickAwayProvider callback={!preventAutoClose && handleClose} refs={clickAwayRefs}>
199
+ <ClickAwayProvider callback={!preventAutoClose && onClose} refs={clickAwayRefs}>
196
200
  <div className={`${CLASSNAME}__wrapper`} ref={wrapperRef}>
197
201
  {(header || headerChildContent) && (
198
202
  <header
@@ -1,5 +1,81 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`<Dialog> Snapshots and structure should render story DialogWithAlertDialog 1`] = `
4
+ <Fragment>
5
+ <Button
6
+ emphasis="high"
7
+ onClick={[Function]}
8
+ size="m"
9
+ theme="light"
10
+ >
11
+ Open dialog
12
+ </Button>
13
+ <Dialog
14
+ isOpen={true}
15
+ onClose={[Function]}
16
+ parentElement={
17
+ Object {
18
+ "current": undefined,
19
+ }
20
+ }
21
+ size="big"
22
+ >
23
+ <div
24
+ className="lumx-spacing-padding"
25
+ >
26
+
27
+ Nihil hic munitissimus habendi senatus locus, nihil horum? At nos hinc posthac, sitientis piros
28
+ Afros. Magna pars studiorum, prodita quaerimus. Integer legentibus erat a ante historiarum
29
+ dapibus. Praeterea iter est quasdam res quas ex communi. Ullamco laboris nisi ut aliquid ex ea
30
+ commodi consequat. Inmensae subtilitatis, obscuris et malesuada fames. Me non paenitet nullum
31
+ festiviorem excogitasse ad hoc. Cum ceteris in veneratione tui montes, nascetur mus. Etiam
32
+ habebis sem dicantur magna mollis euismod. Quis aute iure reprehenderit in voluptate velit esse.
33
+ Phasellus laoreet lorem vel dolor tempus vehicula. Ambitioni dedisse scripsisse iudicaretur.
34
+ Paullum deliquit, ponderibus modulisque suis ratio utitur. Ab illo tempore, ab est sed
35
+ immemorabili. Nec dubitamus multa iter quae et nos invenerat. Tu quoque, Brute, fili mi, nihil
36
+ timor populi, nihil! Morbi fringilla convallis sapien, id pulvinar odio volutpat. Cras mattis
37
+ iudicium purus sit amet fermentum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus.
38
+ Quisque ut dolor gravida, placerat libero vel, euismod. Unam incolunt Belgae, aliam Aquitani,
39
+ tertiam. Cras mattis iudicium purus sit amet fermentum
40
+ </div>
41
+ <footer>
42
+ <Toolbar
43
+ after={
44
+ <Button
45
+ emphasis="low"
46
+ onClick={[Function]}
47
+ size="m"
48
+ theme="light"
49
+ >
50
+ Close
51
+ </Button>
52
+ }
53
+ />
54
+ </footer>
55
+ </Dialog>
56
+ <AlertDialog
57
+ confirmProps={
58
+ Object {
59
+ "label": "Confirm",
60
+ "onClick": [Function],
61
+ }
62
+ }
63
+ isOpen={false}
64
+ kind="info"
65
+ onClose={[Function]}
66
+ parentElement={
67
+ Object {
68
+ "current": undefined,
69
+ }
70
+ }
71
+ size="tiny"
72
+ title="Default (info)"
73
+ >
74
+ Consequat deserunt officia aute laborum tempor anim sint est.
75
+ </AlertDialog>
76
+ </Fragment>
77
+ `;
78
+
3
79
  exports[`<Dialog> Snapshots and structure should render story DialogWithFocusableElements 1`] = `
4
80
  <Fragment>
5
81
  <Button
@@ -40,7 +40,11 @@ export const DragHandle: Comp<DragHandleProps, HTMLDivElement> = forwardRef((pro
40
40
  {...forwardedProps}
41
41
  className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, theme }))}
42
42
  >
43
- <Icon icon={mdiDragVertical} color={theme === Theme.dark ? ColorPalette.light : undefined} size={Size.xs} />
43
+ <Icon
44
+ icon={mdiDragVertical}
45
+ color={theme === Theme.dark ? ColorPalette.light : ColorPalette.dark}
46
+ size={Size.xs}
47
+ />
44
48
  </div>
45
49
  );
46
50
  });
@@ -69,9 +69,8 @@ describe(`<${Flag.displayName} />`, () => {
69
69
 
70
70
  it('should use the color', () => {
71
71
  const color = ColorPalette.green;
72
- const { wrapper, iconEl } = setup({ icon: mdiAbTesting, color });
72
+ const { wrapper } = setup({ icon: mdiAbTesting, color });
73
73
 
74
- expect(iconEl.prop('color')).toEqual(color);
75
74
  expect(wrapper).toHaveClassName(
76
75
  getBasicClass({
77
76
  prefix: CLASSNAME,
@@ -1,7 +1,7 @@
1
1
  import React, { forwardRef } from 'react';
2
2
  import classNames from 'classnames';
3
3
 
4
- import { ColorPalette, ColorVariant, Icon, Size, Theme } from '@lumx/react';
4
+ import { ColorPalette, Icon, Size, Theme } from '@lumx/react';
5
5
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
6
6
 
7
7
  export interface FlagProps extends GenericProps {
@@ -38,15 +38,7 @@ export const Flag: Comp<FlagProps, HTMLDivElement> = forwardRef((props, ref) =>
38
38
  className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, color: flagColor }))}
39
39
  ref={ref}
40
40
  >
41
- {icon && (
42
- <Icon
43
- icon={icon}
44
- color={color}
45
- colorVariant={ColorVariant.D2}
46
- size={Size.xxs}
47
- className={`${CLASSNAME}__icon`}
48
- />
49
- )}
41
+ {icon && <Icon icon={icon} size={Size.xxs} className={`${CLASSNAME}__icon`} />}
50
42
  <span className={`${CLASSNAME}__label`}>{label}</span>
51
43
  </div>
52
44
  );
@@ -19,8 +19,6 @@ Array [
19
19
  >
20
20
  <Icon
21
21
  className="lumx-flag__icon"
22
- color="blue"
23
- colorVariant="D2"
24
22
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
25
23
  size="xxs"
26
24
  />
@@ -35,8 +33,6 @@ Array [
35
33
  >
36
34
  <Icon
37
35
  className="lumx-flag__icon"
38
- color="dark"
39
- colorVariant="D2"
40
36
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
41
37
  size="xxs"
42
38
  />
@@ -51,8 +47,6 @@ Array [
51
47
  >
52
48
  <Icon
53
49
  className="lumx-flag__icon"
54
- color="green"
55
- colorVariant="D2"
56
50
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
57
51
  size="xxs"
58
52
  />
@@ -67,8 +61,6 @@ Array [
67
61
  >
68
62
  <Icon
69
63
  className="lumx-flag__icon"
70
- color="primary"
71
- colorVariant="D2"
72
64
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
73
65
  size="xxs"
74
66
  />
@@ -83,8 +75,6 @@ Array [
83
75
  >
84
76
  <Icon
85
77
  className="lumx-flag__icon"
86
- color="red"
87
- colorVariant="D2"
88
78
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
89
79
  size="xxs"
90
80
  />
@@ -99,8 +89,6 @@ Array [
99
89
  >
100
90
  <Icon
101
91
  className="lumx-flag__icon"
102
- color="secondary"
103
- colorVariant="D2"
104
92
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
105
93
  size="xxs"
106
94
  />
@@ -115,8 +103,6 @@ Array [
115
103
  >
116
104
  <Icon
117
105
  className="lumx-flag__icon"
118
- color="yellow"
119
- colorVariant="D2"
120
106
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
121
107
  size="xxs"
122
108
  />
@@ -135,7 +121,6 @@ exports[`<Flag /> Snapshots and structure should render story 'withIcon' 1`] = `
135
121
  >
136
122
  <Icon
137
123
  className="lumx-flag__icon"
138
- colorVariant="D2"
139
124
  icon="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
140
125
  size="xxs"
141
126
  />
@@ -1,4 +1,4 @@
1
- import { LANDSCAPE_IMAGES, landscapeImageKnob } from '@lumx/react/stories/knobs';
1
+ import { LANDSCAPE_IMAGES, landscapeImageKnob } from '@lumx/react/stories/knobs/image';
2
2
  import React from 'react';
3
3
 
4
4
  import { Alignment, AspectRatio, Chip, ChipGroup, ImageBlock, Size } from '@lumx/react';
@@ -1,5 +1,5 @@
1
1
  /* istanbul ignore file */
2
- import { landscapeImageKnob, portraitImageKnob } from '@lumx/react/stories/knobs';
2
+ import { landscapeImageKnob, portraitImageKnob } from '@lumx/react/stories/knobs/image';
3
3
  import { text } from '@storybook/addon-knobs';
4
4
  import React from 'react';
5
5
  import { Size } from '..';
@@ -46,10 +46,16 @@ export const KeyboardNavigation = () => {
46
46
  <ListItem linkProps={{ href: '#' }}>Link item 2</ListItem>
47
47
  <ListSubheader>Header</ListSubheader>
48
48
  </>
49
+ <ListItem linkProps={{ href: '#' }} isDisabled>
50
+ Disabled link item
51
+ </ListItem>
52
+ <ListItem onItemSelected={action('onItemSelected')} isDisabled>
53
+ Disabled button item
54
+ </ListItem>
49
55
  <CustomListItem />
50
56
  {[
51
57
  <ListItem key="1" linkProps={{ href: '#' }}>
52
- Link item 3
58
+ Link item 4
53
59
  </ListItem>,
54
60
  ]}
55
61
  </List>
@@ -2,12 +2,37 @@ import React from 'react';
2
2
 
3
3
  import { Size } from '@lumx/react';
4
4
  import { select, text } from '@storybook/addon-knobs';
5
+ import { action } from '@storybook/addon-actions';
5
6
 
6
7
  import { ListItem } from './ListItem';
7
8
 
8
9
  export default { title: 'LumX components/list/ListItem' };
9
10
 
10
- export const Default = ({ theme }: any) => <ListItem theme={theme}>{text('text', 'Text')}</ListItem>;
11
+ export const NonClickable = ({ theme }: any) => <ListItem theme={theme}>{text('text', 'Text')}</ListItem>;
12
+
13
+ export const Link = ({ theme }: any) => (
14
+ <ListItem theme={theme} linkProps={{ href: '#' }}>
15
+ {text('text', 'Text')}
16
+ </ListItem>
17
+ );
18
+
19
+ export const Button = ({ theme }: any) => (
20
+ <ListItem theme={theme} onItemSelected={action('onItemSelected')}>
21
+ {text('text', 'Text')}
22
+ </ListItem>
23
+ );
24
+
25
+ export const LinkDisabled = ({ theme }: any) => (
26
+ <ListItem theme={theme} linkProps={{ href: '#' }} isDisabled>
27
+ {text('text', 'Text')}
28
+ </ListItem>
29
+ );
30
+
31
+ export const ButtonDisabled = ({ theme }: any) => (
32
+ <ListItem theme={theme} onItemSelected={action('onItemSelected')} isDisabled>
33
+ {text('text', 'Text')}
34
+ </ListItem>
35
+ );
11
36
 
12
37
  export const Selected = ({ theme }: any) => (
13
38
  <ListItem theme={theme} linkProps={{ href: '#' }} isSelected>
@@ -28,10 +53,10 @@ export const Sizes = ({ theme }: any) => (
28
53
  );
29
54
 
30
55
  const CustomLink: React.FC = ({ children, ...props }) =>
31
- React.createElement('a', { ...props, style: { color: 'red' } }, children);
56
+ React.createElement('a', { ...props, style: { color: 'red' }, href: 'http://google.com' }, children);
32
57
 
33
58
  export const WithCustomLink = ({ theme }: any) => (
34
- <ListItem theme={theme} linkAs={CustomLink} linkProps={{ href: 'http://google.com' }}>
59
+ <ListItem theme={theme} linkAs={CustomLink}>
35
60
  My custom link
36
61
  </ListItem>
37
62
  );
@@ -4,7 +4,14 @@ import classNames from 'classnames';
4
4
  import isEmpty from 'lodash/isEmpty';
5
5
 
6
6
  import { ListProps, Size } from '@lumx/react';
7
- import { Comp, GenericProps, getRootClassName, handleBasicClasses, onEnterPressed } from '@lumx/react/utils';
7
+ import {
8
+ Comp,
9
+ GenericProps,
10
+ getRootClassName,
11
+ handleBasicClasses,
12
+ onEnterPressed,
13
+ onButtonPressed,
14
+ } from '@lumx/react/utils';
8
15
  import { renderLink } from '@lumx/react/utils/renderLink';
9
16
 
10
17
  export type ListItemSize = Extract<Size, 'tiny' | 'regular' | 'big' | 'huge'>;
@@ -23,6 +30,8 @@ export interface ListItemProps extends GenericProps {
23
30
  isHighlighted?: boolean;
24
31
  /** Whether the component is selected or not. */
25
32
  isSelected?: boolean;
33
+ /** Whether link/button is disabled or not. */
34
+ isDisabled?: boolean;
26
35
  /** Reference to the <li> element. */
27
36
  listItemRef?: Ref<HTMLLIElement>;
28
37
  /** Custom react component for the link (can be used to inject react router Link). */
@@ -33,6 +42,7 @@ export interface ListItemProps extends GenericProps {
33
42
  linkRef?: Ref<HTMLAnchorElement>;
34
43
  /** Size variant. */
35
44
  size?: ListItemSize;
45
+
36
46
  /** On selected callback. */
37
47
  onItemSelected?(evt: SyntheticEvent): void;
38
48
  }
@@ -77,6 +87,7 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
77
87
  className,
78
88
  isHighlighted,
79
89
  isSelected,
90
+ isDisabled,
80
91
  linkAs,
81
92
  linkProps = {},
82
93
  linkRef,
@@ -84,9 +95,13 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
84
95
  size,
85
96
  ...forwardedProps
86
97
  } = props;
87
- const onKeyDown = useMemo(() => (onItemSelected ? onEnterPressed(onItemSelected as any) : undefined), [
88
- onItemSelected,
89
- ]);
98
+
99
+ const role = linkAs || linkProps.href ? 'link' : 'button';
100
+ const onKeyDown = useMemo(() => {
101
+ if (onItemSelected && role === 'link') return onEnterPressed(onItemSelected as any);
102
+ if (onItemSelected && role === 'button') return onButtonPressed(onItemSelected as any);
103
+ return undefined;
104
+ }, [role, onItemSelected]);
90
105
 
91
106
  const content = (
92
107
  <>
@@ -113,17 +128,20 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
113
128
  renderLink(
114
129
  {
115
130
  linkAs,
116
- tabIndex: 0,
117
- role: onItemSelected ? 'button' : undefined,
131
+ tabIndex: !isDisabled && role === 'button' ? 0 : undefined,
132
+ role,
133
+ 'aria-disabled': isDisabled,
118
134
  ...linkProps,
135
+ href: isDisabled ? undefined : linkProps.href,
119
136
  className: classNames(
120
137
  handleBasicClasses({
121
138
  prefix: `${CLASSNAME}__link`,
122
139
  isHighlighted,
123
140
  isSelected,
141
+ isDisabled,
124
142
  }),
125
143
  ),
126
- onClick: onItemSelected,
144
+ onClick: isDisabled ? undefined : onItemSelected,
127
145
  onKeyDown,
128
146
  ref: linkRef,
129
147
  },
@@ -129,12 +129,32 @@ exports[`<List> Snapshots and structure should render story 'KeyboardNavigation'
129
129
  >
130
130
  Header
131
131
  </ListSubheader>
132
- <CustomListItem
132
+ <ListItem
133
+ isDisabled={true}
133
134
  key=".4"
135
+ linkProps={
136
+ Object {
137
+ "href": "#",
138
+ }
139
+ }
140
+ size="regular"
141
+ >
142
+ Disabled link item
143
+ </ListItem>
144
+ <ListItem
145
+ isDisabled={true}
146
+ key=".5"
147
+ onItemSelected={[Function]}
148
+ size="regular"
149
+ >
150
+ Disabled button item
151
+ </ListItem>
152
+ <CustomListItem
153
+ key=".6"
134
154
  />
135
155
  <ListItem
136
156
  isHighlighted={false}
137
- key=".5:$1"
157
+ key=".7:$1"
138
158
  linkProps={
139
159
  Object {
140
160
  "href": "#",
@@ -147,7 +167,7 @@ exports[`<List> Snapshots and structure should render story 'KeyboardNavigation'
147
167
  onMouseUp={[Function]}
148
168
  size="regular"
149
169
  >
150
- Link item 3
170
+ Link item 4
151
171
  </ListItem>
152
172
  </ul>
153
173
  `;